mirror of
https://github.com/PDB-REDO/libcifpp.git
synced 2026-06-04 22:14:24 +08:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e7b0baafb | ||
|
|
b3dc38f2d8 | ||
|
|
6044d3dce3 | ||
|
|
29446f2122 | ||
|
|
abb8673549 | ||
|
|
ffc8f9dcdf | ||
|
|
288b2bb720 | ||
|
|
fb3b7bda68 | ||
|
|
6d5efe1cbd | ||
|
|
1ceec22184 | ||
|
|
951ff9b953 | ||
|
|
641f06a7e7 | ||
|
|
915ba4ac21 | ||
|
|
824637d83f | ||
|
|
0871406fe3 | ||
|
|
1ad7e47b2e | ||
|
|
f72a2c69d0 | ||
|
|
84d9275cb8 | ||
|
|
1b7c387c8b | ||
|
|
2f1adbd22c | ||
|
|
65031523a6 | ||
|
|
02cc0fa0f6 | ||
|
|
1e1afa023f |
@@ -25,7 +25,7 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# set the project name
|
||||
project(libcifpp VERSION 5.2.0 LANGUAGES CXX)
|
||||
project(libcifpp VERSION 5.2.4 LANGUAGES CXX)
|
||||
|
||||
list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
|
||||
@@ -36,6 +36,8 @@ include(CheckLibraryExists)
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(CheckCXXSourceCompiles)
|
||||
include(GenerateExportHeader)
|
||||
include(CTest)
|
||||
include(CMakeDependentOption)
|
||||
|
||||
set(CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
@@ -49,9 +51,6 @@ elseif(MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||
endif()
|
||||
|
||||
# Building shared libraries?
|
||||
option(BUILD_SHARED_LIBS "Build a shared library instead of a static one" OFF)
|
||||
|
||||
# Build documentation?
|
||||
option(BUILD_DOCUMENTATION "Build the documentation" OFF)
|
||||
|
||||
@@ -61,6 +60,14 @@ set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
# Optionally build a version to be installed inside CCP4
|
||||
option(BUILD_FOR_CCP4 "Build a version to be installed in CCP4" OFF)
|
||||
|
||||
# Building shared libraries?
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.22)
|
||||
cmake_policy(SET CMP0127 NEW)
|
||||
cmake_dependent_option(BUILD_SHARED_LIBS "Build a shared library instead of a static one" OFF "NOT (BUILD_FOR_CCP4 AND WIN32)" ON)
|
||||
else()
|
||||
option(BUILD_SHARED_LIBS "Build a shared library instead of a static one" OFF)
|
||||
endif()
|
||||
|
||||
# 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)
|
||||
|
||||
@@ -83,8 +90,6 @@ else()
|
||||
endif()
|
||||
|
||||
# Unit tests
|
||||
option(ENABLE_TESTING "Build test exectuables" OFF)
|
||||
|
||||
if(BUILD_FOR_CCP4)
|
||||
if("$ENV{CCP4}" STREQUAL "" OR NOT EXISTS $ENV{CCP4})
|
||||
message(FATAL_ERROR "A CCP4 built was requested but CCP4 was not sourced")
|
||||
@@ -120,7 +125,8 @@ endif()
|
||||
|
||||
if(MSVC)
|
||||
# make msvc standards compliant...
|
||||
add_compile_options(/permissive-)
|
||||
add_compile_options(/permissive- /bigobj)
|
||||
add_link_options(/NODEFAULTLIB:library)
|
||||
|
||||
if(BUILD_SHARED_LIBS)
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
||||
@@ -292,11 +298,11 @@ set_target_properties(cifpp PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
target_include_directories(cifpp
|
||||
PUBLIC
|
||||
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include;${PROJECT_BINARY_DIR};${EIGEN3_INCLUDE_DIR}>"
|
||||
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include;${PROJECT_BINARY_DIR}>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||
)
|
||||
|
||||
target_link_libraries(cifpp PUBLIC Threads::Threads ZLIB::ZLIB Eigen3::Eigen ${CIFPP_REQUIRED_LIBRARIES})
|
||||
target_link_libraries(cifpp PUBLIC Threads::Threads ZLIB::ZLIB ${CIFPP_REQUIRED_LIBRARIES} PRIVATE Eigen3::Eigen)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
target_link_options(cifpp PRIVATE -undefined dynamic_lookup)
|
||||
@@ -318,11 +324,12 @@ if(CIFPP_DOWNLOAD_CCD)
|
||||
endif()
|
||||
|
||||
# Installation directories
|
||||
set(CIFPP_DATA_DIR "${CMAKE_INSTALL_FULL_DATADIR}/libcifpp")
|
||||
set(CIFPP_DATA_DIR "${CMAKE_INSTALL_FULL_DATADIR}/libcifpp" CACHE PATH "The directory where dictionary files are stored")
|
||||
target_compile_definitions(cifpp PUBLIC DATA_DIR="${CIFPP_DATA_DIR}")
|
||||
|
||||
if(UNIX)
|
||||
set(CIFPP_CACHE_DIR "${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/cache/libcifpp")
|
||||
set(CIFPP_CACHE_DIR "${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/cache/libcifpp"
|
||||
CACHE PATH "The directory where the update script stores new dictionary files")
|
||||
target_compile_definitions(cifpp PUBLIC CACHE_DIR="${CIFPP_CACHE_DIR}")
|
||||
|
||||
set(CIFPP_ETC_DIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}")
|
||||
@@ -338,7 +345,7 @@ install(TARGETS cifpp
|
||||
|
||||
if(MSVC AND BUILD_SHARED_LIBS)
|
||||
install(
|
||||
FILES $<TARGET_PDB_FILE:${PROJECT_NAME}>
|
||||
FILES $<TARGET_PDB_FILE:cifpp>
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
OPTIONAL)
|
||||
endif()
|
||||
@@ -395,11 +402,10 @@ install(FILES
|
||||
COMPONENT Devel
|
||||
)
|
||||
|
||||
set(cifpp_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR})
|
||||
set_target_properties(cifpp PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION "${cifpp_MAJOR_VERSION}.${cifpp_MINOR_VERSION}"
|
||||
INTERFACE_cifpp_MAJOR_VERSION ${cifpp_MAJOR_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
|
||||
@@ -411,9 +417,7 @@ write_basic_package_version_file(
|
||||
COMPATIBILITY AnyNewerVersion
|
||||
)
|
||||
|
||||
if(ENABLE_TESTING)
|
||||
enable_testing()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
find_package(Boost REQUIRED)
|
||||
|
||||
list(APPEND CIFPP_tests unit-v2 unit-3d format model rename-compound sugar spinner)
|
||||
|
||||
10
README.md
10
README.md
@@ -2,6 +2,10 @@
|
||||
|
||||
This library contains code to work with mmCIF and legacy PDB files.
|
||||
|
||||
## Documentation
|
||||
|
||||
The documentation can be found at https://www.hekkelman.com/libcifpp-doc/
|
||||
|
||||
## Synopsis
|
||||
|
||||
```c++
|
||||
@@ -108,13 +112,9 @@ This checks out the source code from github, creates a new directory
|
||||
where cmake stores its files. Run a configure, build the code and then
|
||||
it installs the library and auxiliary files.
|
||||
|
||||
If you want to run the tests before installing, you should add `-DENABLE_TESTING=ON`
|
||||
to the first cmake command. So that would be:
|
||||
Tests are created by default, and to test the code you can run:
|
||||
|
||||
```console
|
||||
git clone https://github.com/PDB-REDO/libcifpp.git --recurse-submodules
|
||||
cd libcifpp
|
||||
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=$HOME/.local -DCMAKE_BUILD_TYPE=Release -DENABLE_TESTING=ON
|
||||
cmake --build build
|
||||
ctest --test-dir build
|
||||
```
|
||||
|
||||
20
changelog
20
changelog
@@ -1,3 +1,23 @@
|
||||
Version 5.2.4
|
||||
- Changes required to build on Windows
|
||||
|
||||
Version 5.2.3
|
||||
- New constructors for cif::item, one taking std::optional values
|
||||
and another taking only a name resulting in a value '.' (i.e. inapplicable).
|
||||
- added cif::cell::get_volume
|
||||
|
||||
Version 5.2.2
|
||||
- Remove dependency on Eigen3 for users of libcifpp
|
||||
- Fix typos in documentation
|
||||
- Do not build latex files in documentation
|
||||
- Fixed conversion from string to integer, would fail on +2 e.g.
|
||||
- sqrt is not constexpr, thus kGoldenRatio should be const, not constexpr
|
||||
|
||||
Version 5.2.1
|
||||
- New versionstring module
|
||||
- small fixes for generating documentation
|
||||
- correctly setting SONAME
|
||||
|
||||
Version 5.2.0
|
||||
- With lots of documentation
|
||||
- Refactored coloured text output
|
||||
|
||||
@@ -54,6 +54,10 @@ cmake_minimum_required(VERSION 3.15)
|
||||
variables contained in the revision file.
|
||||
#]=======================================================================]
|
||||
|
||||
# Record the location of this module now, not at the time the CMakeLists.txt
|
||||
# is being processed
|
||||
get_filename_component(_current_cmake_module_dir ${CMAKE_CURRENT_LIST_FILE} PATH)
|
||||
|
||||
# First locate a .git file or directory.
|
||||
function(_get_git_dir _start_dir _variable)
|
||||
|
||||
@@ -233,7 +237,11 @@ function(write_version_header dir)
|
||||
|
||||
if(res EQUAL 0)
|
||||
set(REVISION_STRING "${out}")
|
||||
else()
|
||||
message(STATUS "Git hash not found, does this project has a 'build' tag?")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Git hash not found")
|
||||
endif()
|
||||
|
||||
# Check the revision string, if it matches we fill in the required info
|
||||
@@ -255,141 +263,13 @@ function(write_version_header dir)
|
||||
if(VERSION_STRING_OPTION_LIB_NAME)
|
||||
set(VAR_PREFIX "${VERSION_STRING_OPTION_LIB_NAME}")
|
||||
set(IDENT_PREFIX "${VERSION_STRING_OPTION_LIB_NAME}_")
|
||||
set(BOOL_IS_MAIN "false")
|
||||
else()
|
||||
set(VAR_PREFIX "")
|
||||
set(IDENT_PREFIX "")
|
||||
set(BOOL_IS_MAIN "true")
|
||||
endif()
|
||||
|
||||
# And finally, write out the header file
|
||||
file(WRITE "${VERSION_STRING_DATA}/${file_name}.in" [[// This file was generated by VersionString.cmake
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ostream>
|
||||
|
||||
constexpr const char k@VAR_PREFIX@ProjectName[] = "@PROJECT_NAME@";
|
||||
constexpr const char k@VAR_PREFIX@VersionNumber[] = "@PROJECT_VERSION@";
|
||||
constexpr int k@VAR_PREFIX@BuildNumber = @BUILD_NUMBER@;
|
||||
constexpr const char k@VAR_PREFIX@RevisionGitTag[] = "@REVISION_GIT_TAGREF@";
|
||||
constexpr const char k@VAR_PREFIX@RevisionDate[] = "@REVISION_DATE_TIME@";
|
||||
|
||||
#ifndef VERSION_INFO_DEFINED
|
||||
#define VERSION_INFO_DEFINED 1
|
||||
|
||||
namespace version_info_v1
|
||||
{
|
||||
|
||||
class version_info_base
|
||||
{
|
||||
public:
|
||||
|
||||
static void write(std::ostream &os, bool verbose)
|
||||
{
|
||||
auto &s_head = head();
|
||||
if (s_head != nullptr)
|
||||
write(s_head, os, verbose);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
version_info_base(const char *name, const char *version, int build_number, const char *git_tag, const char *revision_date)
|
||||
: m_name(name)
|
||||
, m_version(version)
|
||||
, m_build_number(build_number)
|
||||
, m_git_tag(git_tag)
|
||||
, m_revision_date(revision_date)
|
||||
{
|
||||
auto &s_head = head();
|
||||
m_next = s_head;
|
||||
s_head = this;
|
||||
}
|
||||
|
||||
static void write(const version_info_base *inst, std::ostream &os, bool verbose)
|
||||
{
|
||||
if (inst->m_next)
|
||||
{
|
||||
write(inst->m_next, os, verbose);
|
||||
|
||||
if (not verbose)
|
||||
return;
|
||||
|
||||
os << '-' << std::endl;
|
||||
}
|
||||
|
||||
os << inst->m_name << " version " << inst->m_version << std::endl;
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
if (inst->m_build_number != 0)
|
||||
{
|
||||
os << "build: " << inst->m_build_number << ' ' << inst->m_revision_date << std::endl;
|
||||
if (inst->m_git_tag[0] != 0)
|
||||
os << "git tag: " << inst->m_git_tag << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using version_info_ptr = version_info_base *;
|
||||
|
||||
static version_info_ptr &head()
|
||||
{
|
||||
static version_info_ptr s_head = nullptr;
|
||||
return s_head;
|
||||
}
|
||||
|
||||
const char *m_name;
|
||||
const char *m_version;
|
||||
int m_build_number;
|
||||
const char *m_git_tag;
|
||||
const char *m_revision_date;
|
||||
version_info_base *m_next = nullptr;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class version_info : public version_info_base
|
||||
{
|
||||
public:
|
||||
using implementation_type = T;
|
||||
|
||||
version_info(const char *name, const char *version, int build_number, const char *git_tag, const char *revision_date)
|
||||
: version_info_base(name, version, build_number, git_tag, revision_date)
|
||||
{
|
||||
}
|
||||
|
||||
struct register_object
|
||||
{
|
||||
register_object()
|
||||
{
|
||||
static implementation_type s_instance;
|
||||
}
|
||||
};
|
||||
|
||||
template<register_object&> struct reference_object;
|
||||
|
||||
static register_object s_registered_object;
|
||||
static reference_object<s_registered_object> s_referenced_object;
|
||||
};
|
||||
|
||||
template<typename T> typename version_info<T>::register_object version_info<T>::s_registered_object;
|
||||
|
||||
}
|
||||
|
||||
inline void write_version_string(std::ostream &os, bool verbose)
|
||||
{
|
||||
version_info_v1::version_info_base::write(os, verbose);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
class version_info_@IDENT_PREFIX@impl : public version_info_v1::version_info<version_info_@IDENT_PREFIX@impl>
|
||||
{
|
||||
public:
|
||||
version_info_@IDENT_PREFIX@impl()
|
||||
: version_info(k@VAR_PREFIX@ProjectName, k@VAR_PREFIX@VersionNumber, k@VAR_PREFIX@BuildNumber, k@VAR_PREFIX@RevisionGitTag, k@VAR_PREFIX@RevisionDate)
|
||||
{
|
||||
}
|
||||
};
|
||||
]])
|
||||
configure_file("${VERSION_STRING_DATA}/${file_name}.in" "${dir}/${file_name}" @ONLY)
|
||||
configure_file("${_current_cmake_module_dir}/revision.hpp.in" "${dir}/${file_name}" @ONLY)
|
||||
endfunction()
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ include(CMakeFindDependencyMacro)
|
||||
find_dependency(Threads)
|
||||
|
||||
find_dependency(ZLIB REQUIRED)
|
||||
find_dependency(Eigen3 REQUIRED)
|
||||
|
||||
if(MSVC)
|
||||
find_dependency(zeep REQUIRED)
|
||||
|
||||
121
cmake/revision.hpp.in
Normal file
121
cmake/revision.hpp.in
Normal file
@@ -0,0 +1,121 @@
|
||||
// This file was generated by VersionString.cmake
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ostream>
|
||||
|
||||
constexpr const char k@VAR_PREFIX@ProjectName[] = "@PROJECT_NAME@";
|
||||
constexpr const char k@VAR_PREFIX@VersionNumber[] = "@PROJECT_VERSION@";
|
||||
constexpr int k@VAR_PREFIX@BuildNumber = @BUILD_NUMBER@;
|
||||
constexpr const char k@VAR_PREFIX@RevisionGitTag[] = "@REVISION_GIT_TAGREF@";
|
||||
constexpr const char k@VAR_PREFIX@RevisionDate[] = "@REVISION_DATE_TIME@";
|
||||
|
||||
#ifndef VERSION_INFO_DEFINED
|
||||
#define VERSION_INFO_DEFINED 1
|
||||
|
||||
namespace version_info_v1_1
|
||||
{
|
||||
|
||||
class version_info_base
|
||||
{
|
||||
public:
|
||||
static void write_version_string(std::ostream &os, bool verbose)
|
||||
{
|
||||
auto s_main = registered_main();
|
||||
if (s_main != nullptr)
|
||||
s_main->write(os, verbose);
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
for (auto lib = registered_libraries(); lib != nullptr; lib = lib->m_next)
|
||||
{
|
||||
os << "-\n";
|
||||
lib->write(os, verbose);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
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)
|
||||
, m_git_tag(git_tag)
|
||||
, m_revision_date(revision_date)
|
||||
{
|
||||
if (is_main)
|
||||
registered_main() = this;
|
||||
else
|
||||
{
|
||||
auto &s_head = registered_libraries();
|
||||
m_next = s_head;
|
||||
s_head = this;
|
||||
}
|
||||
}
|
||||
|
||||
void write(std::ostream &os, bool verbose)
|
||||
{
|
||||
os << m_name << " version " << m_version << '\n';
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
if (m_build_number != 0)
|
||||
{
|
||||
os << "build: " << m_build_number << ' ' << m_revision_date << '\n';
|
||||
if (m_git_tag[0] != 0)
|
||||
os << "git tag: " << m_git_tag << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using version_info_ptr = version_info_base *;
|
||||
|
||||
static version_info_ptr ®istered_main()
|
||||
{
|
||||
static version_info_ptr s_main = nullptr;
|
||||
return s_main;
|
||||
}
|
||||
|
||||
static version_info_ptr ®istered_libraries()
|
||||
{
|
||||
static version_info_ptr s_head = nullptr;
|
||||
return s_head;
|
||||
}
|
||||
|
||||
const char *m_name;
|
||||
const char *m_version;
|
||||
int m_build_number;
|
||||
const char *m_git_tag;
|
||||
const char *m_revision_date;
|
||||
version_info_base *m_next = nullptr;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class version_info : public version_info_base
|
||||
{
|
||||
public:
|
||||
using implementation_type = T;
|
||||
|
||||
version_info(const char *name, const char *version, int build_number, const char *git_tag, const char *revision_date, bool is_main)
|
||||
: version_info_base(name, version, build_number, git_tag, revision_date, is_main)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace version_info_v1_1
|
||||
|
||||
inline void write_version_string(std::ostream &os, bool verbose)
|
||||
{
|
||||
version_info_v1_1::version_info_base::write_version_string(os, verbose);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
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()
|
||||
: 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;
|
||||
@@ -7,36 +7,42 @@ set(CIFPP_PUBLIC_HEADER_DIR ${PROJECT_SOURCE_DIR}/include)
|
||||
file(GLOB_RECURSE CIFPP_PUBLIC_HEADERS ${CIFPP_PUBLIC_HEADER_DIR}/*.hpp)
|
||||
|
||||
set(DOXYGEN_INPUT_DIR ${CIFPP_PUBLIC_HEADER_DIR})
|
||||
set(DOXYGEN_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(DOXYGEN_INDEX_FILE ${DOXYGEN_OUTPUT_DIR}/xml/index.xml)
|
||||
set(DOXYGEN_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/xml)
|
||||
set(DOXYGEN_INDEX_FILE ${DOXYGEN_OUTPUT_DIR}/index.xml)
|
||||
set(DOXYFILE_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)
|
||||
set(DOXYFILE_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
|
||||
|
||||
#Replace variables inside @@ with the current values
|
||||
# Replace variables inside @@ with the current values
|
||||
configure_file(${DOXYFILE_IN} ${DOXYFILE_OUT} @ONLY)
|
||||
|
||||
file(MAKE_DIRECTORY ${DOXYGEN_OUTPUT_DIR}/xml) #Doxygen won't create this for us
|
||||
add_custom_command(OUTPUT ${DOXYGEN_INDEX_FILE}
|
||||
BYPRODUCTS ${DOXYGEN_OUTPUT_DIR}/xml
|
||||
DEPENDS ${CIFPP_PUBLIC_HEADERS} ${DOXYFILE_OUT}
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT}
|
||||
MAIN_DEPENDENCY ${DOXYFILE_OUT} ${DOXYFILE_IN}
|
||||
COMMENT "Generating docs")
|
||||
add_custom_command(
|
||||
OUTPUT ${DOXYGEN_OUTPUT_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${DOXYGEN_OUTPUT_DIR})
|
||||
|
||||
add_custom_target(Doxygen ALL DEPENDS ${DOXYGEN_INDEX_FILE})
|
||||
add_custom_command(OUTPUT ${DOXYGEN_INDEX_FILE}
|
||||
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 ALL
|
||||
COMMAND ${SPHINX_EXECUTABLE} -b html
|
||||
-Dbreathe_projects.${PROJECT_NAME}=${DOXYGEN_OUTPUT_DIR}/xml
|
||||
${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")
|
||||
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/sphinx/ DESTINATION ${CMAKE_INSTALL_DOCDIR} PATTERN .doctrees EXCLUDE)
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/sphinx/
|
||||
DESTINATION ${CMAKE_INSTALL_DOCDIR}
|
||||
PATTERN .doctrees EXCLUDE
|
||||
PATTERN .buildinfo EXCLUDE)
|
||||
|
||||
@@ -3,6 +3,7 @@ FILE_PATTERNS = *.hpp
|
||||
STRIP_FROM_PATH = @DOXYGEN_INPUT_DIR@
|
||||
RECURSIVE = YES
|
||||
GENERATE_XML = YES
|
||||
GENERATE_LATEX = NO
|
||||
PREDEFINED += and=&& or=|| not=! CIFPP_EXPORT= HAVE_LIBCLIPPER=1
|
||||
GENERATE_HTML = NO
|
||||
GENERATE_TODOLIST = NO
|
||||
|
||||
@@ -26,7 +26,7 @@ Writing is equally easy:
|
||||
file << "Hello, world!";
|
||||
file.close();
|
||||
|
||||
You can also use the :cpp:class:`cif::gzio:istream` and feed it a *std::streambuf* object that may or may not contain compressed data. In that case the first bytes of the input are sniffed and if it is gzip compressed data, decompression will be done.
|
||||
You can also use the :cpp:class:`cif::gzio::istream` and feed it a *std::streambuf* object that may or may not contain compressed data. In that case the first bytes of the input are sniffed and if it is gzip compressed data, decompression will be done.
|
||||
|
||||
A progress bar
|
||||
--------------
|
||||
|
||||
@@ -9,4 +9,25 @@ Information about compounds is captured in the :cpp:class:`cif::compound`. An in
|
||||
|
||||
If the compound you want to use is not available in the CCD or in CCP4, you can add that information yourself. For this you can use the method :cpp:func:`cif::compound_factory::push_dictionary`.
|
||||
|
||||
So, given that we have CCD, CCP4 monomer library and used defined compound definitions, what will you get when you try to retrieve such a compound by ID? The answer is, the factory has a stack of compound generators. The first thrown on the stack is the one for a CCD file (*components.cif*) if it can be found. Then, if the *CLIBD_MON* environmental variable is defined, a generator for monomer library files is added to the stack. And then all generators for files you added using *push_dictionary* are added in order. The generators are searched in the reverse order in which they were added to see if it creates a compound object for the ID. If no compound was created at all, nullptr is returned.
|
||||
So, given that we have CCD, CCP4 monomer library and used defined compound definitions, what will you get when you try to retrieve such a compound by ID? The answer is, the factory has a stack of compound generators. The first thrown on the stack is the one for a CCD file (*components.cif*) if it can be found. Then, if the *CLIBD_MON* environmental variable is defined, a generator for monomer library files is added to the stack. And then all generators for files you added using *push_dictionary* are added in order. The generators are searched in the reverse order in which they were added to see if it creates a compound object for the ID. If no compound was created at all, nullptr is returned.
|
||||
|
||||
Updating CCD
|
||||
------------
|
||||
|
||||
The CCD data is stored in a single file called *components.cif* and can be downloaded from `CCD <https://www.wwpdb.org/data/ccd>`_.
|
||||
|
||||
As can be read in the section on resources (:doc:`/resources`) files in libcifpp are loaded in a specific order. If the CCD datafile was downloaded during installation, a copy can be found in the directory */usr/share/libcifpp/* (if you installed in */usr*). This is a static file and will not be updated until the next installation of libcifpp.
|
||||
|
||||
When configuring libcifpp, you can specify the *CIFPP_INSTALL_UPDATE_SCRIPT* option, as in:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
cmake -S . -B build -DCIFPP_INSTALL_UPDATE_SCRIPT=ON # ... more options?
|
||||
|
||||
This will install a script named *update-libcifpp-data* in */etc/cron.weekly* or */etc/periodic/weekly*. This file uses a config file named */etc/libcifpp.conf* which you then need to edit. In this config file the following line needs to be uncommented:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
# update=true
|
||||
|
||||
After that, the update script will weekly download the latest components.cif file to */var/cache/libcifpp*.
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "cif++/exports.hpp"
|
||||
#include "cif++/datablock.hpp"
|
||||
#include "cif++/parser.hpp"
|
||||
|
||||
|
||||
@@ -26,8 +26,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/exports.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
@@ -51,14 +51,51 @@ namespace cif
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/// \brief item is a transient class that is used to pass data into rows
|
||||
/// but it also takes care of formatting data.
|
||||
/** @brief item is a transient class that is used to pass data into rows
|
||||
* but it also takes care of formatting data.
|
||||
*
|
||||
*
|
||||
*
|
||||
* The class cif::item is often used implicitly when creating a row in a category
|
||||
* using the emplace function.
|
||||
*
|
||||
* @code{.cpp}
|
||||
* cif::category cat("my-cat");
|
||||
* cat.emplace({
|
||||
* { "item-1", 1 }, // <- stores an item with value 1
|
||||
* { "item-2", 1.0, 2 }, // <- stores an item with value 1.00
|
||||
* { "item-3", std::optional<int>() }, // <- stores an item with value ?
|
||||
* { "item-4", std::make_optional<int>(42) }, // <- stores an item with value 42
|
||||
* { "item-5" } // <- stores an item with value .
|
||||
* });
|
||||
*
|
||||
* std::cout << cat << '\n';
|
||||
* @endcode
|
||||
*
|
||||
* Will result in:
|
||||
*
|
||||
* @code{.txt}
|
||||
* _my-cat.item-1 1
|
||||
* _my-cat.item-2 1.00
|
||||
* _my-cat.item-3 ?
|
||||
* _my-cat.item-4 42
|
||||
* _my-cat.item-5 .
|
||||
* @endcode
|
||||
*/
|
||||
class item
|
||||
{
|
||||
public:
|
||||
/// \brief Default constructor, empty item
|
||||
item() = default;
|
||||
|
||||
/// \brief constructor for an item with name \a name and as
|
||||
/// content the character '.', i.e. an inapplicable value.
|
||||
item(std::string_view name)
|
||||
: m_name(name)
|
||||
, m_value({ '.' })
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief constructor for an item with name \a name and as
|
||||
/// content a single character string with content \a value
|
||||
item(std::string_view name, char value)
|
||||
@@ -68,7 +105,7 @@ class item
|
||||
}
|
||||
|
||||
/// \brief constructor for an item with name \a name and as
|
||||
/// content a the formatted floating point value \a value with
|
||||
/// content the formatted floating point value \a value with
|
||||
/// precision \a precision
|
||||
template <typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
|
||||
item(std::string_view name, const T &value, int precision)
|
||||
@@ -110,7 +147,7 @@ class item
|
||||
}
|
||||
|
||||
/// \brief constructor for an item with name \a name and as
|
||||
/// content a the formatted integral value \a value
|
||||
/// content the formatted integral value \a value
|
||||
template <typename T, std::enable_if_t<std::is_integral_v<T> and not std::is_same_v<T, bool>, int> = 0>
|
||||
item(const std::string_view name, const T &value)
|
||||
: m_name(name)
|
||||
@@ -127,7 +164,7 @@ class item
|
||||
}
|
||||
|
||||
/// \brief constructor for an item with name \a name and as
|
||||
/// content a the formatted boolean value \a value
|
||||
/// content the formatted boolean value \a value
|
||||
template <typename T, std::enable_if_t<std::is_same_v<T, bool>, int> = 0>
|
||||
item(const std::string_view name, const T &value)
|
||||
: m_name(name)
|
||||
@@ -143,6 +180,37 @@ class item
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief constructor for an item with name \a name and as
|
||||
/// content the optional value \a value
|
||||
template <typename T>
|
||||
item(const std::string_view name, const std::optional<T> &value)
|
||||
: m_name(name)
|
||||
{
|
||||
if (value.has_value())
|
||||
{
|
||||
item tmp(name, *value);
|
||||
std::swap(tmp.m_value, m_value);
|
||||
}
|
||||
else
|
||||
m_value.assign("?");
|
||||
}
|
||||
|
||||
/// \brief constructor for an item with name \a name and as
|
||||
/// content the formatted floating point value \a value with
|
||||
/// precision \a precision
|
||||
template <typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
|
||||
item(std::string_view name, const std::optional<T> &value, int precision)
|
||||
: m_name(name)
|
||||
{
|
||||
if (value.has_value())
|
||||
{
|
||||
item tmp(name, *value, precision);
|
||||
std::swap(tmp.m_value, m_value);
|
||||
}
|
||||
else
|
||||
m_value.assign("?");
|
||||
}
|
||||
|
||||
/** @cond */
|
||||
item(const item &rhs) = default;
|
||||
item(item &&rhs) noexcept = default;
|
||||
@@ -287,7 +355,7 @@ struct item_handle
|
||||
|
||||
/**
|
||||
* @brief Assign value @a value to the item referenced
|
||||
*
|
||||
*
|
||||
* @tparam T Type of the value
|
||||
* @param value The value
|
||||
* @return reference to this item_handle
|
||||
@@ -459,9 +527,12 @@ struct item_handle::item_value_as<T, std::enable_if_t<std::is_arithmetic_v<T> an
|
||||
{
|
||||
auto txt = ref.text();
|
||||
|
||||
std::from_chars_result r = selected_charconv<value_type>::from_chars(txt.data(), txt.data() + txt.size(), result);
|
||||
auto b = txt.data();
|
||||
auto e = txt.data() + txt.size();
|
||||
|
||||
if (r.ec != std::errc())
|
||||
std::from_chars_result r = (b + 1 < e and *b == '+' and std::isdigit(b[1])) ? selected_charconv<value_type>::from_chars(b + 1, e, result) : selected_charconv<value_type>::from_chars(b, e, result);
|
||||
|
||||
if (r.ec != std::errc() or r.ptr != e)
|
||||
{
|
||||
result = {};
|
||||
if (cif::VERBOSE)
|
||||
@@ -470,6 +541,8 @@ struct item_handle::item_value_as<T, std::enable_if_t<std::is_arithmetic_v<T> an
|
||||
std::cerr << "Attempt to convert " << std::quoted(txt) << " into a number\n";
|
||||
else if (r.ec == std::errc::result_out_of_range)
|
||||
std::cerr << "Conversion of " << std::quoted(txt) << " into a type that is too small\n";
|
||||
else
|
||||
std::cerr << "Not a valid number " << std::quoted(txt) << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -489,9 +562,12 @@ struct item_handle::item_value_as<T, std::enable_if_t<std::is_arithmetic_v<T> an
|
||||
{
|
||||
value_type v = {};
|
||||
|
||||
std::from_chars_result r = selected_charconv<value_type>::from_chars(txt.data(), txt.data() + txt.size(), v);
|
||||
auto b = txt.data();
|
||||
auto e = txt.data() + txt.size();
|
||||
|
||||
if (r.ec != std::errc())
|
||||
std::from_chars_result r = (b + 1 < e and *b == '+' and std::isdigit(b[1])) ? selected_charconv<value_type>::from_chars(b + 1, e, v) : selected_charconv<value_type>::from_chars(b, e, v);
|
||||
|
||||
if (r.ec != std::errc() or r.ptr != e)
|
||||
{
|
||||
if (cif::VERBOSE)
|
||||
{
|
||||
@@ -499,6 +575,8 @@ struct item_handle::item_value_as<T, std::enable_if_t<std::is_arithmetic_v<T> an
|
||||
std::cerr << "Attempt to convert " << std::quoted(txt) << " into a number\n";
|
||||
else if (r.ec == std::errc::result_out_of_range)
|
||||
std::cerr << "Conversion of " << std::quoted(txt) << " into a type that is too small\n";
|
||||
else
|
||||
std::cerr << "Not a valid number " << std::quoted(txt) << '\n';
|
||||
}
|
||||
result = 1;
|
||||
}
|
||||
|
||||
@@ -26,8 +26,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cif++/exports.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <complex>
|
||||
@@ -882,7 +880,7 @@ class spherical_dots
|
||||
|
||||
spherical_dots()
|
||||
{
|
||||
constexpr double
|
||||
const double
|
||||
kGoldenRatio = (1 + std::sqrt(5.0)) / 2;
|
||||
|
||||
auto p = m_points.begin();
|
||||
|
||||
@@ -397,6 +397,8 @@ class cell
|
||||
float get_beta() const { return m_beta; } ///< return angle beta
|
||||
float get_gamma() const { return m_gamma; } ///< return angle gamma
|
||||
|
||||
float get_volume() const; ///< return the calculated volume for this cell
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -77,6 +77,9 @@ extern CIFPP_EXPORT int VERBOSE;
|
||||
/// return the git 'build' number
|
||||
std::string get_version_nr();
|
||||
|
||||
/// return the width of the current output terminal, or 80 if it cannot be determined
|
||||
uint32_t get_terminal_width();
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
namespace colour
|
||||
|
||||
10
src/file.cpp
10
src/file.cpp
@@ -182,17 +182,17 @@ std::tuple<file::iterator, bool> file::emplace(std::string_view name)
|
||||
|
||||
void file::load(const std::filesystem::path &p)
|
||||
{
|
||||
gzio::ifstream in(p);
|
||||
if (not in.is_open())
|
||||
throw std::runtime_error("Could not open file '" + p.string() + '\'');
|
||||
|
||||
try
|
||||
{
|
||||
gzio::ifstream in(p);
|
||||
if (not in.is_open())
|
||||
throw std::runtime_error("Could not open file " + p.string());
|
||||
|
||||
load(in);
|
||||
}
|
||||
catch (const std::exception &)
|
||||
{
|
||||
throw_with_nested(std::runtime_error("Error reading file " + p.string()));
|
||||
throw_with_nested(std::runtime_error("Error reading file '" + p.string() + '\''));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -80,6 +80,22 @@ void cell::init()
|
||||
m_fractional = inverse(m_orthogonal);
|
||||
}
|
||||
|
||||
float cell::get_volume() const
|
||||
{
|
||||
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);
|
||||
|
||||
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 vol;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
sym_op::sym_op(std::string_view s)
|
||||
|
||||
@@ -43,11 +43,6 @@
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
|
||||
#if not defined(_WIN32)
|
||||
#include <sys/ioctl.h>
|
||||
#include <termios.h>
|
||||
#endif
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -88,6 +83,8 @@ uint32_t get_terminal_width()
|
||||
|
||||
#else
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <termios.h>
|
||||
#include <limits.h>
|
||||
|
||||
uint32_t get_terminal_width()
|
||||
|
||||
BIN
test/.1juh.cif.gz.swp
Normal file
BIN
test/.1juh.cif.gz.swp
Normal file
Binary file not shown.
@@ -90,7 +90,7 @@ BOOST_AUTO_TEST_CASE(clr_1)
|
||||
{
|
||||
using namespace cif::colour;
|
||||
|
||||
std::cout << "Hello, " << cif::coloured("world!", white, red, regular) << '\n'
|
||||
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'
|
||||
|
||||
@@ -565,8 +565,6 @@ BOOST_AUTO_TEST_CASE(symm_2bi3_1a, *utf::tolerance(0.1f))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(symm_3bwh_1, *utf::tolerance(0.1f))
|
||||
{
|
||||
cif::file f(gTestDir / "3bwh.cif.gz");
|
||||
@@ -588,4 +586,16 @@ BOOST_AUTO_TEST_CASE(symm_3bwh_1, *utf::tolerance(0.1f))
|
||||
BOOST_TEST(d == distance(a1.get_location(), p));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(volume_3bwh_1, *utf::tolerance(0.1f))
|
||||
{
|
||||
cif::file f(gTestDir / "1juh.cif.gz");
|
||||
|
||||
auto &db = f.front();
|
||||
|
||||
cif::crystal c(db);
|
||||
|
||||
BOOST_CHECK_EQUAL(c.get_cell().get_volume(), 741009.625f);
|
||||
}
|
||||
|
||||
|
||||
@@ -150,6 +150,31 @@ BOOST_AUTO_TEST_CASE(cc_2)
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cc_3)
|
||||
{
|
||||
cif::category c("foo");
|
||||
c.emplace({
|
||||
{ "f-1", 1 },
|
||||
{ "f-2", "-1" },
|
||||
{ "f-3", "+1" },
|
||||
{ "f-4", " 1" },
|
||||
{ "f-5", " +1" },
|
||||
{ "f-6", "1 " },
|
||||
});
|
||||
|
||||
auto row = c.front();
|
||||
BOOST_CHECK_EQUAL(row["f-1"].as<int>(), 1);
|
||||
BOOST_CHECK_EQUAL(row["f-2"].as<int>(), -1);
|
||||
BOOST_CHECK_EQUAL(row["f-3"].as<int>(), 1);
|
||||
|
||||
// BOOST_CHECK_THROW(row["f-4"].as<int>(), std::exception);
|
||||
// BOOST_CHECK_THROW(row["f-5"].as<int>(), std::exception);
|
||||
// BOOST_CHECK_THROW(row["f-6"].as<int>(), std::exception);
|
||||
BOOST_CHECK_EQUAL(row["f-4"].as<int>(), 0);
|
||||
BOOST_CHECK_EQUAL(row["f-5"].as<int>(), 0);
|
||||
BOOST_CHECK_EQUAL(row["f-6"].as<int>(), 0);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(item_1)
|
||||
{
|
||||
using namespace cif;
|
||||
@@ -179,6 +204,26 @@ BOOST_AUTO_TEST_CASE(item_1)
|
||||
BOOST_CHECK(ci3.empty());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(item_2)
|
||||
{
|
||||
using namespace cif;
|
||||
|
||||
cif::item i0("test1");
|
||||
BOOST_CHECK(i0.value() == ".");
|
||||
|
||||
cif::item i1("test1", std:: optional<float>());
|
||||
BOOST_CHECK(i1.value() == "?");
|
||||
|
||||
cif::item i2("test1", std::make_optional<float>(1));
|
||||
BOOST_CHECK(i2.value() == "1");
|
||||
|
||||
cif::item i3("test1", std::optional<float>(), 2);
|
||||
BOOST_CHECK(i3.value() == "?");
|
||||
|
||||
cif::item i4("test1", std::make_optional<float>(1), 2);
|
||||
BOOST_CHECK(i4.value() == "1.00");
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
BOOST_AUTO_TEST_CASE(r_1)
|
||||
|
||||
Reference in New Issue
Block a user