Commit a855f880 by Maarten L. Hekkelman

Getting rid of boost/algorithm/string

parent cfa2acd6
...@@ -6,10 +6,10 @@ ...@@ -6,10 +6,10 @@
# modification, are permitted provided that the following conditions are met: # modification, are permitted provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright notice, this # 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer # list of conditions and the following disclaimer
# 2. Redistributions in binary form must reproduce the above copyright notice, # 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation # this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution. # and/or other materials provided with the distribution.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # 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 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
...@@ -46,7 +46,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) ...@@ -46,7 +46,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") 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) elseif(MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
endif() endif()
# Building shared libraries? # Building shared libraries?
...@@ -57,6 +57,7 @@ set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) ...@@ -57,6 +57,7 @@ set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
# Optionally build a version to be installed inside CCP4 # Optionally build a version to be installed inside CCP4
option(BUILD_FOR_CCP4 "Build a version to be installed in CCP4" OFF) option(BUILD_FOR_CCP4 "Build a version to be installed in CCP4" OFF)
if(BUILD_FOR_CCP4) if(BUILD_FOR_CCP4)
if("$ENV{CCP4}" STREQUAL "" OR NOT EXISTS $ENV{CCP4}) if("$ENV{CCP4}" STREQUAL "" OR NOT EXISTS $ENV{CCP4})
message(FATAL_ERROR "A CCP4 built was requested but CCP4 was not sourced") message(FATAL_ERROR "A CCP4 built was requested but CCP4 was not sourced")
...@@ -79,6 +80,7 @@ if(EXISTS "$ENV{CCP4}") ...@@ -79,6 +80,7 @@ if(EXISTS "$ENV{CCP4}")
set(CCP4 $ENV{CCP4}) set(CCP4 $ENV{CCP4})
set(CLIBD ${CCP4}/lib/data) set(CLIBD ${CCP4}/lib/data)
endif() endif()
if(CCP4 AND NOT CLIBD) if(CCP4 AND NOT CLIBD)
set(CLIBD ${CCP4}/lib/data) set(CLIBD ${CCP4}/lib/data)
endif() endif()
...@@ -97,13 +99,12 @@ else() ...@@ -97,13 +99,12 @@ else()
endif() endif()
# set(CMAKE_DEBUG_POSTFIX d) # set(CMAKE_DEBUG_POSTFIX d)
if(MSVC) if(MSVC)
# make msvc standards compliant... # make msvc standards compliant...
add_compile_options(/permissive-) add_compile_options(/permissive-)
macro(get_WIN32_WINNT version) macro(get_WIN32_WINNT version)
if (WIN32 AND CMAKE_SYSTEM_VERSION) if(WIN32 AND CMAKE_SYSTEM_VERSION)
set(ver ${CMAKE_SYSTEM_VERSION}) set(ver ${CMAKE_SYSTEM_VERSION})
string(REPLACE "." "" ver ${ver}) string(REPLACE "." "" ver ${ver})
string(REGEX REPLACE "([0-9])" "0\\1" ver ${ver}) string(REGEX REPLACE "([0-9])" "0\\1" ver ${ver})
...@@ -129,7 +130,6 @@ if(UNIX AND NOT APPLE AND NOT BUILD_FOR_CCP4 AND CMAKE_INSTALL_PREFIX_INITIALIZE ...@@ -129,7 +130,6 @@ if(UNIX AND NOT APPLE AND NOT BUILD_FOR_CCP4 AND CMAKE_INSTALL_PREFIX_INITIALIZE
endif() endif()
# Optionally use mrc to create resources # Optionally use mrc to create resources
if(WIN32 AND BUILD_SHARED_LIBS) if(WIN32 AND BUILD_SHARED_LIBS)
message("Not using resources when building shared libraries for Windows") message("Not using resources when building shared libraries for Windows")
else() else()
...@@ -150,17 +150,12 @@ else() ...@@ -150,17 +150,12 @@ else()
endif() endif()
# Libraries # Libraries
set(CMAKE_THREAD_PREFER_PTHREAD) set(CMAKE_THREAD_PREFER_PTHREAD)
set(THREADS_PREFER_PTHREAD_FLAG) set(THREADS_PREFER_PTHREAD_FLAG)
find_package(Threads) find_package(Threads)
find_package(Boost 1.70.0 REQUIRED COMPONENTS system iostreams regex program_options) find_package(Boost 1.70.0 REQUIRED COMPONENTS system regex program_options)
find_package(gzstream REQUIRED)
if(NOT MSVC AND Boost_USE_STATIC_LIBS)
find_package(ZLIB REQUIRED)
list(APPEND CIFPP_REQUIRED_LIBRARIES ZLIB::ZLIB)
endif()
include(FindFilesystem) include(FindFilesystem)
list(APPEND CIFPP_REQUIRED_LIBRARIES ${STDCPPFS_LIBRARY}) list(APPEND CIFPP_REQUIRED_LIBRARIES ${STDCPPFS_LIBRARY})
...@@ -175,21 +170,21 @@ write_version_header("LibCIFPP") ...@@ -175,21 +170,21 @@ write_version_header("LibCIFPP")
# SymOp data table # SymOp data table
if(CIFPP_RECREATE_SYMOP_DATA) if(CIFPP_RECREATE_SYMOP_DATA)
# The tool to create the table # The tool to create the table
add_executable(symop-map-generator "${CMAKE_SOURCE_DIR}/tools/symop-map-generator.cpp") add_executable(symop-map-generator "${CMAKE_SOURCE_DIR}/tools/symop-map-generator.cpp")
target_link_libraries(symop-map-generator Threads::Threads ${Boost_LIBRARIES} ${CIFPP_REQUIRED_LIBRARIES}) target_link_libraries(symop-map-generator Threads::Threads ${Boost_LIBRARIES} ${CIFPP_REQUIRED_LIBRARIES})
if(Boost_INCLUDE_DIR) if(Boost_INCLUDE_DIR)
target_include_directories(symop-map-generator PUBLIC ${Boost_INCLUDE_DIR}) target_include_directories(symop-map-generator PUBLIC ${Boost_INCLUDE_DIR})
endif() endif()
set($ENV{CLIBD} ${CLIBD}) set($ENV{CLIBD} ${CLIBD})
add_custom_command( add_custom_command(
OUTPUT ${CMAKE_SOURCE_DIR}/src/SymOpTable_data.hpp OUTPUT ${CMAKE_SOURCE_DIR}/src/SymOpTable_data.hpp
COMMAND $<TARGET_FILE:symop-map-generator> ${CLIBD}/syminfo.lib ${CMAKE_SOURCE_DIR}/src/SymOpTable_data.hpp COMMAND $<TARGET_FILE:symop-map-generator> ${CLIBD}/syminfo.lib ${CMAKE_SOURCE_DIR}/src/SymOpTable_data.hpp
) )
add_custom_target( add_custom_target(
OUTPUT ${CMAKE_SOURCE_DIR}/src/SymOpTable_data.hpp OUTPUT ${CMAKE_SOURCE_DIR}/src/SymOpTable_data.hpp
DEPENDS symop-map-generator "$ENV{CLIBD}/syminfo.lib" DEPENDS symop-map-generator "$ENV{CLIBD}/syminfo.lib"
...@@ -197,8 +192,7 @@ if(CIFPP_RECREATE_SYMOP_DATA) ...@@ -197,8 +192,7 @@ if(CIFPP_RECREATE_SYMOP_DATA)
endif() endif()
# Sources # Sources
set(project_sources
set(project_sources
${PROJECT_SOURCE_DIR}/src/AtomType.cpp ${PROJECT_SOURCE_DIR}/src/AtomType.cpp
${PROJECT_SOURCE_DIR}/src/BondMap.cpp ${PROJECT_SOURCE_DIR}/src/BondMap.cpp
${PROJECT_SOURCE_DIR}/src/Cif++.cpp ${PROJECT_SOURCE_DIR}/src/Cif++.cpp
...@@ -224,7 +218,7 @@ set(project_sources ...@@ -224,7 +218,7 @@ set(project_sources
${PROJECT_SOURCE_DIR}/src/v2/validate.cpp ${PROJECT_SOURCE_DIR}/src/v2/validate.cpp
) )
set(project_headers set(project_headers
${PROJECT_SOURCE_DIR}/include/cif++/AtomType.hpp ${PROJECT_SOURCE_DIR}/include/cif++/AtomType.hpp
${PROJECT_SOURCE_DIR}/include/cif++/BondMap.hpp ${PROJECT_SOURCE_DIR}/include/cif++/BondMap.hpp
${PROJECT_SOURCE_DIR}/include/cif++/Cif++.hpp ${PROJECT_SOURCE_DIR}/include/cif++/Cif++.hpp
...@@ -249,7 +243,7 @@ target_include_directories(cifpp ...@@ -249,7 +243,7 @@ target_include_directories(cifpp
PUBLIC PUBLIC
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>" "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>" "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
${Boost_INCLUDE_DIR} ${Boost_INCLUDE_DIR} ${gzstream_INCLUDE_DIR}
) )
target_include_directories(cifpp target_include_directories(cifpp
...@@ -257,21 +251,21 @@ target_include_directories(cifpp ...@@ -257,21 +251,21 @@ target_include_directories(cifpp
${CMAKE_BINARY_DIR} ${CMAKE_BINARY_DIR}
) )
target_link_libraries(cifpp PUBLIC Threads::Threads Boost::regex Boost::iostreams ${CIFPP_REQUIRED_LIBRARIES}) target_link_libraries(cifpp PUBLIC Threads::Threads Boost::regex gzstream::gzstream ${CIFPP_REQUIRED_LIBRARIES})
# target_link_libraries(cifpp PRIVATE)
if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") # target_link_libraries(cifpp PRIVATE)
target_link_options(cifpp PRIVATE -undefined dynamic_lookup) if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
endif (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") target_link_options(cifpp PRIVATE -undefined dynamic_lookup)
endif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
option(CIFPP_DOWNLOAD_CCD "Download the CCD file components.cif during installation" OFF) option(CIFPP_DOWNLOAD_CCD "Download the CCD file components.cif during installation" OFF)
if(CIFPP_DOWNLOAD_CCD) if(CIFPP_DOWNLOAD_CCD)
# download the components.cif file from CCD # download the components.cif file from CCD
set(COMPONENTS_CIF ${PROJECT_SOURCE_DIR}/data/components.cif) set(COMPONENTS_CIF ${PROJECT_SOURCE_DIR}/data/components.cif)
if (NOT EXISTS ${COMPONENTS_CIF}) if(NOT EXISTS ${COMPONENTS_CIF})
if(NOT EXISTS ${PROJECT_SOURCE_DIR}/data)
if (NOT EXISTS ${PROJECT_SOURCE_DIR}/data)
file(MAKE_DIRECTORY ${PROJECT_SOURCE_DIR}/data/) file(MAKE_DIRECTORY ${PROJECT_SOURCE_DIR}/data/)
endif() endif()
...@@ -301,8 +295,8 @@ endif() ...@@ -301,8 +295,8 @@ endif()
generate_export_header(cifpp generate_export_header(cifpp
EXPORT_FILE_NAME cif++/Cif++Export.hpp) EXPORT_FILE_NAME cif++/Cif++Export.hpp)
set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR} ) set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR})
set(LIBRARY_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR} ) set(LIBRARY_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR})
set(SHARE_INSTALL_DIR ${CMAKE_INSTALL_DATADIR}/libcifpp) set(SHARE_INSTALL_DIR ${CMAKE_INSTALL_DATADIR}/libcifpp)
set(CIFPP_DATA_DIR "${CMAKE_INSTALL_PREFIX}/${SHARE_INSTALL_DIR}" CACHE STRING "The directory containing the provided data files") set(CIFPP_DATA_DIR "${CMAKE_INSTALL_PREFIX}/${SHARE_INSTALL_DIR}" CACHE STRING "The directory containing the provided data files")
...@@ -310,7 +304,6 @@ set(CIFPP_DATA_DIR "${CMAKE_INSTALL_PREFIX}/${SHARE_INSTALL_DIR}" CACHE STRING " ...@@ -310,7 +304,6 @@ set(CIFPP_DATA_DIR "${CMAKE_INSTALL_PREFIX}/${SHARE_INSTALL_DIR}" CACHE STRING "
target_compile_definitions(cifpp PUBLIC DATA_DIR="${CIFPP_DATA_DIR}") target_compile_definitions(cifpp PUBLIC DATA_DIR="${CIFPP_DATA_DIR}")
# Install rules # Install rules
install(TARGETS cifpp install(TARGETS cifpp
EXPORT cifppTargets EXPORT cifppTargets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
...@@ -357,8 +350,8 @@ configure_package_config_file(Config.cmake.in ...@@ -357,8 +350,8 @@ configure_package_config_file(Config.cmake.in
) )
install(FILES install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifppConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifppConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifppConfigVersion.cmake" "${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifppConfigVersion.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cifpp DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cifpp
COMPONENT Devel COMPONENT Devel
) )
...@@ -370,21 +363,20 @@ set_target_properties(cifpp PROPERTIES ...@@ -370,21 +363,20 @@ set_target_properties(cifpp PROPERTIES
INTERFACE_cifpp_MAJOR_VERSION ${cifpp_MAJOR_VERSION}) INTERFACE_cifpp_MAJOR_VERSION ${cifpp_MAJOR_VERSION})
set_property(TARGET cifpp APPEND PROPERTY set_property(TARGET cifpp APPEND PROPERTY
COMPATIBLE_INTERFACE_STRING cifpp_MAJOR_VERSION COMPATIBLE_INTERFACE_STRING cifpp_MAJOR_VERSION
) )
write_basic_package_version_file( write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifppConfigVersion.cmake" "${CMAKE_CURRENT_BINARY_DIR}/cifpp/cifppConfigVersion.cmake"
VERSION ${PROJECT_VERSION} VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion COMPATIBILITY AnyNewerVersion
) )
# pkgconfig support # pkgconfig support
set(prefix ${CMAKE_INSTALL_PREFIX})
set(prefix ${CMAKE_INSTALL_PREFIX})
set(exec_prefix ${CMAKE_INSTALL_PREFIX}) set(exec_prefix ${CMAKE_INSTALL_PREFIX})
set(libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) set(libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR})
set(includedir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}) set(includedir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR})
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libcifpp.pc.in configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libcifpp.pc.in
${CMAKE_CURRENT_BINARY_DIR}/libcifpp.pc.in @ONLY) ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.pc.in @ONLY)
...@@ -393,12 +385,11 @@ file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.pc ...@@ -393,12 +385,11 @@ file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.pc
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
# Unit tests # Unit tests
option(CIFPP_BUILD_TESTS "Build test exectuables" OFF) option(CIFPP_BUILD_TESTS "Build test exectuables" OFF)
if(CIFPP_BUILD_TESTS) if(CIFPP_BUILD_TESTS)
list(APPEND CIFPP_tests list(APPEND CIFPP_tests
# pdb2cif # pdb2cif
rename-compound rename-compound
structure structure
...@@ -414,10 +405,10 @@ if(CIFPP_BUILD_TESTS) ...@@ -414,10 +405,10 @@ if(CIFPP_BUILD_TESTS)
target_include_directories(${CIFPP_TEST} PRIVATE target_include_directories(${CIFPP_TEST} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_BINARY_DIR} # for config.h ${CMAKE_CURRENT_BINARY_DIR} # for config.h
) )
target_link_libraries(${CIFPP_TEST} PRIVATE Threads::Threads cifpp ) target_link_libraries(${CIFPP_TEST} PRIVATE Threads::Threads cifpp)
if(CIFPP_USE_RSRC) if(CIFPP_USE_RSRC)
mrc_target_resources(${CIFPP_TEST} ${CMAKE_SOURCE_DIR}/rsrc/mmcif_pdbx_v50.dic) mrc_target_resources(${CIFPP_TEST} ${CMAKE_SOURCE_DIR}/rsrc/mmcif_pdbx_v50.dic)
...@@ -436,14 +427,12 @@ if(CIFPP_BUILD_TESTS) ...@@ -436,14 +427,12 @@ if(CIFPP_BUILD_TESTS)
add_test(NAME ${CIFPP_TEST} add_test(NAME ${CIFPP_TEST}
COMMAND $<TARGET_FILE:${CIFPP_TEST}> -- ${CMAKE_SOURCE_DIR}/test) COMMAND $<TARGET_FILE:${CIFPP_TEST}> -- ${CMAKE_SOURCE_DIR}/test)
endforeach() endforeach()
endif() endif()
message("Will install in ${CMAKE_INSTALL_PREFIX}") message("Will install in ${CMAKE_INSTALL_PREFIX}")
# Optionally install the update scripts for CCD and dictionary files # Optionally install the update scripts for CCD and dictionary files
if(CIFPP_INSTALL_UPDATE_SCRIPT) if(CIFPP_INSTALL_UPDATE_SCRIPT)
set(CIFPP_CRON_DIR "$ENV{DESTDIR}/etc/cron.weekly") set(CIFPP_CRON_DIR "$ENV{DESTDIR}/etc/cron.weekly")
...@@ -468,4 +457,3 @@ if(CIFPP_INSTALL_UPDATE_SCRIPT) ...@@ -468,4 +457,3 @@ if(CIFPP_INSTALL_UPDATE_SCRIPT)
target_compile_definitions(cifpp PUBLIC CACHE_DIR="${CIFPP_CACHE_DIR}") target_compile_definitions(cifpp PUBLIC CACHE_DIR="${CIFPP_CACHE_DIR}")
endif() endif()
...@@ -2,10 +2,8 @@ ...@@ -2,10 +2,8 @@
include(CMakeFindDependencyMacro) include(CMakeFindDependencyMacro)
find_dependency(Threads) find_dependency(Threads)
find_dependency(Boost 1.70.0 REQUIRED COMPONENTS system iostreams regex) find_dependency(Boost 1.70.0 REQUIRED COMPONENTS system regex)
if(NOT WIN32) find_dependency(gzstream)
find_dependency(ZLIB)
endif()
INCLUDE("${CMAKE_CURRENT_LIST_DIR}/cifppTargets.cmake") INCLUDE("${CMAKE_CURRENT_LIST_DIR}/cifppTargets.cmake")
......
...@@ -72,7 +72,124 @@ bool iequals(const char *a, const char *b); ...@@ -72,7 +72,124 @@ bool iequals(const char *a, const char *b);
int icompare(const char *a, const char *b); int icompare(const char *a, const char *b);
void toLower(std::string &s); void toLower(std::string &s);
std::string toLowerCopy(const std::string &s); std::string toLowerCopy(std::string_view s);
void toUpper(std::string &s);
// std::string toUpperCopy(const std::string &s);
template <typename IterType>
std::string join(IterType b, IterType e, std::string_view sep)
{
std::ostringstream s;
if (b != e)
{
auto ai = b;
auto ni = std::next(ai);
for (;;)
{
s << *ai;
ai = ni;
ni = std::next(ai);
if (ni == e)
break;
s << sep;
}
}
return s.str();
}
template <typename V>
std::string join(const V &arr, std::string_view sep)
{
return join(arr.begin(), arr.end(), sep);
}
template<typename StringType = std::string_view>
std::vector<StringType> split(std::string_view s, std::string_view separators, bool suppress_empty = false)
{
std::vector<StringType> result;
auto b = s.begin();
auto e = b;
while (e != s.end())
{
if (separators.find(*e) != std::string_view::npos)
{
if (e > b or not suppress_empty)
result.emplace_back(b, e - b);
b = e = e + 1;
continue;
}
++e;
}
if (e > b or not suppress_empty)
result.emplace_back(b, e - b);
return result;
}
void replace_all(std::string &s, std::string_view what, std::string_view with = {});
#if defined(__cpp_lib_starts_ends_with)
inline bool starts_with(std::string s, std::string_view with)
{
return s.starts_with(with);
}
inline bool ends_with(std::string_view s, std::string_view with)
{
return s.ends_with(with);
}
#else
inline bool starts_with(std::string s, std::string_view with)
{
return s.compare(0, with.length(), with) == 0;
}
inline bool ends_with(std::string_view s, std::string_view with)
{
return s.length() >= with.length() and s.compare(s.length() - with.length(), with.length(), with) == 0;
}
#endif
#if defined(__cpp_lib_string_contains)
inline bool contains(std::string_view s, std::string_view q)
{
return s.contains(q);
}
#else
inline bool contains(std::string_view s, std::string_view q)
{
return s.find(q) != std::string_view::npos;
}
#endif
bool icontains(std::string_view s, std::string_view q);
void trim_left(std::string &s);
void trim_right(std::string &s);
void trim(std::string &s);
std::string trim_left_copy(std::string_view s);
std::string trim_right_copy(std::string_view s);
std::string trim_copy(std::string_view s);
// To make life easier, we also define iless and iset using iequals // To make life easier, we also define iless and iset using iequals
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
#pragma once #pragma once
#include <vector>
namespace mmcif namespace mmcif
{ {
......
...@@ -599,8 +599,6 @@ class File : public cif::File ...@@ -599,8 +599,6 @@ class File : public cif::File
void load(const std::filesystem::path &p) override; void load(const std::filesystem::path &p) override;
void save(const std::filesystem::path &p) override; void save(const std::filesystem::path &p) override;
void load(std::istream &is) override;
using cif::File::load; using cif::File::load;
using cif::File::save; using cif::File::save;
......
...@@ -394,6 +394,34 @@ class category ...@@ -394,6 +394,34 @@ class category
} }
// -------------------------------------------------------------------- // --------------------------------------------------------------------
/// \brief generate a new, unique ID. Pass it an ID generating function
/// based on a sequence number. This function will be called until the
/// result is unique in the context of this category
std::string get_unique_id(std::function<std::string(int)> generator = cif::cifIdForNumber);
std::string get_unique_id(const std::string &prefix)
{
return get_unique_id([prefix](int nr)
{ return prefix + std::to_string(nr + 1); });
}
// --------------------------------------------------------------------
/// \brief Rename a single column in the rows that match \a cond to value \a value
/// making sure the linked categories are updated according to the link.
/// That means, child categories are updated if the links are absolute
/// and unique. If they are not, the child category rows are split.
void update_value(condition &&cond, std::string_view tag, std::string_view value)
{
auto rs = find(std::move(cond));
std::vector<row_handle> rows;
std::copy(rs.begin(), rs.end(), std::back_inserter(rows));
update_value(rows, tag, value);
}
void update_value(const std::vector<row_handle> &rows, std::string_view tag, std::string_view value);
// --------------------------------------------------------------------
/// \brief Return the index number for \a column_name /// \brief Return the index number for \a column_name
uint16_t get_column_ix(std::string_view column_name) const uint16_t get_column_ix(std::string_view column_name) const
...@@ -573,6 +601,8 @@ class category ...@@ -573,6 +601,8 @@ class category
} }
} }
row_handle create_copy(row_handle r);
struct item_column struct item_column
{ {
std::string m_name; std::string m_name;
...@@ -607,6 +637,7 @@ class category ...@@ -607,6 +637,7 @@ class category
const category_validator *m_cat_validator = nullptr; const category_validator *m_cat_validator = nullptr;
std::vector<link> m_parent_links, m_child_links; std::vector<link> m_parent_links, m_child_links;
bool m_cascade = true; bool m_cascade = true;
uint32_t m_last_unique_num = 0;
class category_index* m_index = nullptr; class category_index* m_index = nullptr;
row *m_head = nullptr, *m_tail = nullptr; row *m_head = nullptr, *m_tail = nullptr;
}; };
......
...@@ -452,8 +452,9 @@ struct item_handle::item_value_as<T, std::enable_if_t<std::is_same_v<T, std::str ...@@ -452,8 +452,9 @@ struct item_handle::item_value_as<T, std::enable_if_t<std::is_same_v<T, std::str
{ {
static std::string convert(const item_handle &ref) static std::string convert(const item_handle &ref)
{ {
std::string_view txt = ref.text(); if (ref.empty())
return {txt.data(), txt.size()}; return {};
return {ref.text().data(), ref.text().size()};
} }
static int compare(const item_handle &ref, const std::string &value, bool icase) static int compare(const item_handle &ref, const std::string &value, bool icase)
......
...@@ -31,16 +31,10 @@ ...@@ -31,16 +31,10 @@
// duh.. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86164 // duh.. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86164
// #include <regex> // #include <regex>
// TODO: get rid of boost::iostreams
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/regex.hpp> #include <boost/regex.hpp>
#include <cif++/CifUtils.hpp> #include <cif++/CifUtils.hpp>
namespace io = boost::iostreams;
namespace cif::v2 namespace cif::v2
{ {
......
...@@ -38,9 +38,8 @@ ...@@ -38,9 +38,8 @@
#include <filesystem> #include <filesystem>
#include <boost/algorithm/string.hpp> #include <gzstream/gzstream.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/logic/tribool.hpp> #include <boost/logic/tribool.hpp>
#include <cif++/Cif++.hpp> #include <cif++/Cif++.hpp>
...@@ -48,8 +47,6 @@ ...@@ -48,8 +47,6 @@
#include <cif++/CifUtils.hpp> #include <cif++/CifUtils.hpp>
#include <cif++/CifValidator.hpp> #include <cif++/CifValidator.hpp>
namespace ba = boost::algorithm;
namespace io = boost::iostreams;
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace cif namespace cif
...@@ -622,10 +619,10 @@ bool operator==(const cif::Datablock &dbA, const cif::Datablock &dbB) ...@@ -622,10 +619,10 @@ bool operator==(const cif::Datablock &dbA, const cif::Datablock &dbB)
while (catA_i != catA.end() and catB_i != catB.end()) while (catA_i != catA.end() and catB_i != catB.end())
{ {
std::string nA = *catA_i; std::string nA = *catA_i;
ba::to_lower(nA); toLower(nA);
std::string nB = *catB_i; std::string nB = *catB_i;
ba::to_lower(nB); toLower(nB);
int d = nA.compare(nB); int d = nA.compare(nB);
if (d > 0) if (d > 0)
...@@ -654,11 +651,11 @@ bool operator==(const cif::Datablock &dbA, const cif::Datablock &dbB) ...@@ -654,11 +651,11 @@ bool operator==(const cif::Datablock &dbA, const cif::Datablock &dbB)
{ {
std::cerr << "compare of datablocks failed" << std::endl; std::cerr << "compare of datablocks failed" << std::endl;
if (not missingA.empty()) if (not missingA.empty())
std::cerr << "Categories missing in A: " << ba::join(missingA, ", ") << std::endl std::cerr << "Categories missing in A: " << cif::join(missingA, ", ") << std::endl
<< std::endl; << std::endl;
if (not missingB.empty()) if (not missingB.empty())
std::cerr << "Categories missing in B: " << ba::join(missingB, ", ") << std::endl std::cerr << "Categories missing in B: " << cif::join(missingB, ", ") << std::endl
<< std::endl; << std::endl;
result = false; result = false;
...@@ -673,10 +670,10 @@ bool operator==(const cif::Datablock &dbA, const cif::Datablock &dbB) ...@@ -673,10 +670,10 @@ bool operator==(const cif::Datablock &dbA, const cif::Datablock &dbB)
while (catA_i != catA.end() and catB_i != catB.end()) while (catA_i != catA.end() and catB_i != catB.end())
{ {
std::string nA = *catA_i; std::string nA = *catA_i;
ba::to_lower(nA); toLower(nA);
std::string nB = *catB_i; std::string nB = *catB_i;
ba::to_lower(nB); toLower(nB);
int d = nA.compare(nB); int d = nA.compare(nB);
if (d > 0) if (d > 0)
...@@ -2156,7 +2153,7 @@ bool Category::isValid() ...@@ -2156,7 +2153,7 @@ bool Category::isValid()
if (not mandatory.empty()) if (not mandatory.empty())
{ {
mValidator->reportError("In Category " + mName + " the following mandatory fields are missing: " + ba::join(mandatory, ", "), false); mValidator->reportError("In Category " + mName + " the following mandatory fields are missing: " + cif::join(mandatory, ", "), false);
result = false; result = false;
} }
...@@ -2447,12 +2444,12 @@ namespace detail ...@@ -2447,12 +2444,12 @@ namespace detail
{ {
if (value.find('\n') != std::string::npos or width == 0 or value.length() > 132) // write as text field if (value.find('\n') != std::string::npos or width == 0 or value.length() > 132) // write as text field
{ {
ba::replace_all(value, "\n;", "\n\\;"); cif::replace_all(value, "\n;", "\n\\;");
if (offset > 0) if (offset > 0)
os << std::endl; os << std::endl;
os << ';' << value; os << ';' << value;
if (not ba::ends_with(value, "\n")) if (not cif::ends_with(value, "\n"))
os << std::endl; os << std::endl;
os << ';' << std::endl; os << ';' << std::endl;
offset = 0; offset = 0;
...@@ -3451,48 +3448,50 @@ void File::load(const std::filesystem::path &p) ...@@ -3451,48 +3448,50 @@ void File::load(const std::filesystem::path &p)
{ {
fs::path path(p); fs::path path(p);
std::ifstream inFile(p, std::ios_base::in | std::ios_base::binary);
if (not inFile.is_open())
throw std::runtime_error("Could not open file: " + path.string());
io::filtering_stream<io::input> in;
std::string ext;
if (path.extension() == ".gz") if (path.extension() == ".gz")
{ {
in.push(io::gzip_decompressor()); gzstream::ifstream in(p);
ext = path.stem().extension().string();
}
in.push(inFile);
try try
{ {
load(in); load(in);
}
catch (const std::exception &ex)
{
if (cif::VERBOSE >= 0)
std::cerr << "Error loading file " << path << std::endl;
throw;
}
} }
catch (const std::exception &ex) else
{ {
if (cif::VERBOSE >= 0) std::ifstream inFile(p, std::ios_base::in | std::ios_base::binary);
std::cerr << "Error loading file " << path << std::endl;
throw; try
{
load(inFile);
}
catch (const std::exception &ex)
{
if (cif::VERBOSE >= 0)
std::cerr << "Error loading file " << path << std::endl;
throw;
}
} }
} }
void File::save(const std::filesystem::path &p) void File::save(const std::filesystem::path &p)
{ {
fs::path path(p); if (p.extension() == ".gz")
std::ofstream outFile(p, std::ios_base::out | std::ios_base::binary);
io::filtering_stream<io::output> out;
if (path.extension() == ".gz")
{ {
out.push(io::gzip_compressor()); gzstream::ofstream outFile(p);
path = path.stem(); save(outFile);
}
else
{
std::ofstream outFile(p, std::ios_base::out | std::ios_base::binary);
save(outFile);
} }
out.push(outFile);
save(out);
} }
void File::load(std::istream &is) void File::load(std::istream &is)
...@@ -3534,14 +3533,16 @@ void File::load(const char *data, std::size_t length) ...@@ -3534,14 +3533,16 @@ void File::load(const char *data, std::size_t length)
membuf(char *data, size_t length) { this->setg(data, data, data + length); } membuf(char *data, size_t length) { this->setg(data, data, data + length); }
} buffer(const_cast<char *>(data), length); } buffer(const_cast<char *>(data), length);
std::istream is(&buffer);
io::filtering_stream<io::input> in;
if (gzipped) if (gzipped)
in.push(io::gzip_decompressor()); {
in.push(is); gzstream::istream is(&buffer);
load(is);
load(is); }
else
{
std::istream is(&buffer);
load(is);
}
} }
void File::save(std::ostream &os) void File::save(std::ostream &os)
......
...@@ -26,14 +26,10 @@ ...@@ -26,14 +26,10 @@
#include <set> #include <set>
#include <boost/algorithm/string.hpp>
#include <cif++/Cif++.hpp> #include <cif++/Cif++.hpp>
#include <cif++/CifParser.hpp> #include <cif++/CifParser.hpp>
#include <cif++/CifValidator.hpp> #include <cif++/CifValidator.hpp>
namespace ba = boost::algorithm;
extern int VERBOSE; extern int VERBOSE;
namespace cif namespace cif
...@@ -1300,9 +1296,9 @@ bool DictParser::collectItemTypes() ...@@ -1300,9 +1296,9 @@ bool DictParser::collectItemTypes()
std::string code, primitiveCode, construct; std::string code, primitiveCode, construct;
cif::tie(code, primitiveCode, construct) = t.get("code", "primitive_code", "construct"); cif::tie(code, primitiveCode, construct) = t.get("code", "primitive_code", "construct");
ba::replace_all(construct, "\\n", "\n"); cif::replace_all(construct, "\\n", "\n");
ba::replace_all(construct, "\\t", "\t"); cif::replace_all(construct, "\\t", "\t");
ba::replace_all(construct, "\\\n", ""); cif::replace_all(construct, "\\\n", "");
try try
{ {
......
/*- /*-
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
* *
* Copyright (c) 2020 NKI/AVL, Netherlands Cancer Institute * Copyright (c) 2020 NKI/AVL, Netherlands Cancer Institute
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this * 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer * list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice, * 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation * this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution. * and/or other materials provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * 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 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
*/ */
#include <atomic> #include <atomic>
#include <cassert>
#include <cmath> #include <cmath>
#include <fstream> #include <fstream>
#include <iomanip> #include <iomanip>
...@@ -42,13 +43,10 @@ ...@@ -42,13 +43,10 @@
#include <termios.h> #include <termios.h>
#endif #endif
#include <boost/algorithm/string.hpp>
#include <cif++/CifUtils.hpp> #include <cif++/CifUtils.hpp>
#include "revision.hpp" #include "revision.hpp"
namespace ba = boost::algorithm;
namespace fs = std::filesystem; namespace fs = std::filesystem;
// -------------------------------------------------------------------- // --------------------------------------------------------------------
...@@ -96,7 +94,7 @@ bool iequals(std::string_view a, std::string_view b) ...@@ -96,7 +94,7 @@ bool iequals(std::string_view a, std::string_view b)
bool result = a.length() == b.length(); bool result = a.length() == b.length();
for (auto ai = a.begin(), bi = b.begin(); result and ai != a.end(); ++ai, ++bi) for (auto ai = a.begin(), bi = b.begin(); result and ai != a.end(); ++ai, ++bi)
result = kCharToLowerMap[uint8_t(*ai)] == kCharToLowerMap[uint8_t(*bi)]; result = kCharToLowerMap[uint8_t(*ai)] == kCharToLowerMap[uint8_t(*bi)];
// result = tolower(*ai) == tolower(*bi); // result = tolower(*ai) == tolower(*bi);
return result; return result;
} }
...@@ -152,7 +150,7 @@ void toLower(std::string &s) ...@@ -152,7 +150,7 @@ void toLower(std::string &s)
c = tolower(c); c = tolower(c);
} }
std::string toLowerCopy(const std::string &s) std::string toLowerCopy(std::string_view s)
{ {
std::string result(s); std::string result(s);
for (auto &c : result) for (auto &c : result)
...@@ -160,6 +158,91 @@ std::string toLowerCopy(const std::string &s) ...@@ -160,6 +158,91 @@ std::string toLowerCopy(const std::string &s)
return result; return result;
} }
void toUpper(std::string &s)
{
for (auto &c : s)
c = toupper(c);
}
void replace_all(std::string &s, std::string_view what, std::string_view with)
{
for (std::string::size_type p = s.find(what); p != std::string::npos; p = s.find(what, p))
s.replace(p, what.length(), with);
}
bool icontains(std::string_view s, std::string_view q)
{
return contains(toLowerCopy(s), toLowerCopy(q));
}
void trim_right(std::string &s)
{
auto e = s.end();
while (e != s.begin())
{
auto pe = std::prev(e);
if (not std::isspace(*pe))
break;
e = pe;
}
if (e != s.end())
s.erase(e, s.end());
}
std::string trim_right_copy(std::string_view s)
{
auto e = s.end();
while (e != s.begin())
{
auto pe = std::prev(e);
if (not std::isspace(*pe))
break;
e = pe;
}
return {s.begin(), e};
}
std::string trim_left_copy(std::string_view s)
{
auto b = s.begin();
while (b != s.end())
{
if (not std::isspace(*b))
break;
b = std::next(b);
}
return {b, s.end()};
}
void trim_left(std::string &s)
{
auto b = s.begin();
while (b != s.end())
{
if (not std::isspace(*b))
break;
b = std::next(b);
}
s.erase(s.begin(), b);
}
void trim(std::string &s)
{
trim_right(s);
trim_left(s);
}
std::string trim_copy(std::string_view s)
{
return trim_left_copy(trim_right_copy(s));
}
// -------------------------------------------------------------------- // --------------------------------------------------------------------
std::tuple<std::string, std::string> splitTagName(std::string_view tag) std::tuple<std::string, std::string> splitTagName(std::string_view tag)
...@@ -181,7 +264,7 @@ std::tuple<std::string, std::string> splitTagName(std::string_view tag) ...@@ -181,7 +264,7 @@ std::tuple<std::string, std::string> splitTagName(std::string_view tag)
std::string cifIdForNumber(int number) std::string cifIdForNumber(int number)
{ {
std::string result; std::string result;
if (number >= 26 * 26 * 26) if (number >= 26 * 26 * 26)
result = 'L' + std::to_string(number); result = 'L' + std::to_string(number);
else else
...@@ -192,17 +275,17 @@ std::string cifIdForNumber(int number) ...@@ -192,17 +275,17 @@ std::string cifIdForNumber(int number)
result += char('A' - 1 + v); result += char('A' - 1 + v);
number %= (26 * 26); number %= (26 * 26);
} }
if (number >= 26) if (number >= 26)
{ {
int v = number / 26; int v = number / 26;
result += char('A' - 1 + v); result += char('A' - 1 + v);
number %= 26; number %= 26;
} }
result += char('A' + number); result += char('A' + number);
} }
assert(not result.empty()); assert(not result.empty());
return result; return result;
} }
...@@ -433,11 +516,8 @@ std::vector<std::string> wrapLine(const std::string &text, size_t width) ...@@ -433,11 +516,8 @@ std::vector<std::string> wrapLine(const std::string &text, size_t width)
std::vector<std::string> wordWrap(const std::string &text, size_t width) std::vector<std::string> wordWrap(const std::string &text, size_t width)
{ {
std::vector<std::string> paragraphs;
ba::split(paragraphs, text, ba::is_any_of("\n"));
std::vector<std::string> result; std::vector<std::string> result;
for (auto &p : paragraphs) for (auto p : cif::split<std::string>(text, "\n"))
{ {
if (p.empty()) if (p.empty())
{ {
...@@ -482,12 +562,15 @@ std::string GetExecutablePath() ...@@ -482,12 +562,15 @@ std::string GetExecutablePath()
// convert from utf16 to utf8 // convert from utf16 to utf8
std::wstring_convert<std::codecvt_utf8<wchar_t>> conv1; std::wstring_convert<std::codecvt_utf8<wchar_t>> conv1;
std::string u8str = conv1.to_bytes(ws); std::string u8str = conv1.to_bytes(ws);
return u8str; return u8str;
} }
#else #else
#include <limits.h>
uint32_t get_terminal_width() uint32_t get_terminal_width()
{ {
uint32_t result = 80; uint32_t result = 80;
...@@ -786,9 +869,9 @@ struct rsrc_imp ...@@ -786,9 +869,9 @@ struct rsrc_imp
#if _MSC_VER #if _MSC_VER
extern "C" const mrsrc::rsrc_imp* gResourceIndexDefault[1] = {}; extern "C" const mrsrc::rsrc_imp *gResourceIndexDefault[1] = {};
extern "C" const char* gResourceDataDefault[1] = {}; extern "C" const char *gResourceDataDefault[1] = {};
extern "C" const char* gResourceNameDefault[1] = {}; extern "C" const char *gResourceNameDefault[1] = {};
extern "C" const mrsrc::rsrc_imp gResourceIndex[]; extern "C" const mrsrc::rsrc_imp gResourceIndex[];
extern "C" const char gResourceData[]; extern "C" const char gResourceData[];
...@@ -1250,12 +1333,14 @@ class ResourcePool ...@@ -1250,12 +1333,14 @@ class ResourcePool
result.reset(file.release()); result.reset(file.release());
} }
} }
catch (...) {} catch (...)
{
}
return result; return result;
} }
std::map<std::string,std::filesystem::path> mLocalResources; std::map<std::string, std::filesystem::path> mLocalResources;
std::deque<fs::path> mDirs; std::deque<fs::path> mDirs;
}; };
...@@ -1301,7 +1386,7 @@ std::unique_ptr<std::istream> ResourcePool::load(fs::path name) ...@@ -1301,7 +1386,7 @@ std::unique_ptr<std::istream> ResourcePool::load(fs::path name)
result.reset(new mrsrc::istream(rsrc)); result.reset(new mrsrc::istream(rsrc));
} }
return result; return result;
} }
// -------------------------------------------------------------------- // --------------------------------------------------------------------
......
...@@ -27,17 +27,13 @@ ...@@ -27,17 +27,13 @@
#include <fstream> #include <fstream>
#include <filesystem> #include <filesystem>
#include <boost/algorithm/string.hpp> #include <gzstream/gzstream.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <cif++/Cif++.hpp> #include <cif++/Cif++.hpp>
#include <cif++/CifParser.hpp> #include <cif++/CifParser.hpp>
#include <cif++/CifValidator.hpp> #include <cif++/CifValidator.hpp>
namespace ba = boost::algorithm;
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace io = boost::iostreams;
extern int VERBOSE; extern int VERBOSE;
...@@ -416,15 +412,11 @@ const Validator &ValidatorFactory::operator[](std::string_view dictionary) ...@@ -416,15 +412,11 @@ const Validator &ValidatorFactory::operator[](std::string_view dictionary)
if (fs::exists(p, ec) and not ec) if (fs::exists(p, ec) and not ec)
{ {
std::ifstream file(p, std::ios::binary); gzstream::ifstream file(p);
if (not file.is_open()) if (not file.is_open())
throw std::runtime_error("Could not open dictionary (" + p.string() + ")"); throw std::runtime_error("Could not open dictionary (" + p.string() + ")");
io::filtering_stream<io::input> in; mValidators.emplace_back(dictionary, file);
in.push(io::gzip_decompressor());
in.push(file);
mValidators.emplace_back(dictionary, in);
} }
else else
throw std::runtime_error("Dictionary not found or defined (" + dict_name.string() + ")"); throw std::runtime_error("Dictionary not found or defined (" + dict_name.string() + ")");
......
...@@ -29,8 +29,6 @@ ...@@ -29,8 +29,6 @@
#include <numeric> #include <numeric>
#include <shared_mutex> #include <shared_mutex>
#include <boost/algorithm/string.hpp>
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
...@@ -40,7 +38,6 @@ ...@@ -40,7 +38,6 @@
#include <cif++/Compound.hpp> #include <cif++/Compound.hpp>
#include <cif++/Point.hpp> #include <cif++/Point.hpp>
namespace ba = boost::algorithm;
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace mmcif namespace mmcif
...@@ -126,7 +123,7 @@ Compound::Compound(cif::Datablock &db) ...@@ -126,7 +123,7 @@ Compound::Compound(cif::Datablock &db)
chemComp.front().get("id", "name", "type", "formula", "formula_weight", "pdbx_formal_charge"); chemComp.front().get("id", "name", "type", "formula", "formula_weight", "pdbx_formal_charge");
// The name should not contain newline characters since that triggers validation errors later on // The name should not contain newline characters since that triggers validation errors later on
ba::replace_all(mName, "\n", ""); cif::replace_all(mName, "\n", "");
mGroup = "non-polymer"; mGroup = "non-polymer";
...@@ -286,7 +283,7 @@ class CompoundFactoryImpl : public std::enable_shared_from_this<CompoundFactoryI ...@@ -286,7 +283,7 @@ class CompoundFactoryImpl : public std::enable_shared_from_this<CompoundFactoryI
{ {
std::shared_lock lock(mMutex); std::shared_lock lock(mMutex);
ba::to_upper(id); cif::toUpper(id);
Compound *result = nullptr; Compound *result = nullptr;
...@@ -554,7 +551,7 @@ CCP4CompoundFactoryImpl::CCP4CompoundFactoryImpl(const fs::path &clibd_mon, std: ...@@ -554,7 +551,7 @@ CCP4CompoundFactoryImpl::CCP4CompoundFactoryImpl(const fs::path &clibd_mon, std:
{ {
if (std::regex_match(group, peptideRx)) if (std::regex_match(group, peptideRx))
mKnownPeptides.insert(threeLetterCode); mKnownPeptides.insert(threeLetterCode);
else if (ba::iequals(group, "DNA") or ba::iequals(group, "RNA")) else if (cif::iequals(group, "DNA") or cif::iequals(group, "RNA"))
mKnownBases.insert(threeLetterCode); mKnownBases.insert(threeLetterCode);
} }
} }
...@@ -576,10 +573,10 @@ Compound *CCP4CompoundFactoryImpl::create(const std::string &id) ...@@ -576,10 +573,10 @@ Compound *CCP4CompoundFactoryImpl::create(const std::string &id)
cif::tie(name, group, numberAtomsAll, numberAtomsNh) = cif::tie(name, group, numberAtomsAll, numberAtomsNh) =
row.get("name", "group", "number_atoms_all", "number_atoms_nh"); row.get("name", "group", "number_atoms_all", "number_atoms_nh");
fs::path resFile = mCLIBD_MON / ba::to_lower_copy(id.substr(0, 1)) / (id + ".cif"); fs::path resFile = mCLIBD_MON / cif::toLowerCopy(id.substr(0, 1)) / (id + ".cif");
if (not fs::exists(resFile) and (id == "COM" or id == "CON" or "PRN")) // seriously... if (not fs::exists(resFile) and (id == "COM" or id == "CON" or "PRN")) // seriously...
resFile = mCLIBD_MON / ba::to_lower_copy(id.substr(0, 1)) / (id + '_' + id + ".cif"); resFile = mCLIBD_MON / cif::toLowerCopy(id.substr(0, 1)) / (id + '_' + id + ".cif");
if (fs::exists(resFile)) if (fs::exists(resFile))
{ {
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
#include <map> #include <map>
#include <set> #include <set>
#include <boost/algorithm/string.hpp>
#include <boost/format.hpp> #include <boost/format.hpp>
#include <cif++/AtomType.hpp> #include <cif++/AtomType.hpp>
...@@ -37,8 +36,6 @@ ...@@ -37,8 +36,6 @@
#include <cif++/PDB2CifRemark3.hpp> #include <cif++/PDB2CifRemark3.hpp>
#include <cif++/CifUtils.hpp> #include <cif++/CifUtils.hpp>
namespace ba = boost::algorithm;
using cif::Datablock; using cif::Datablock;
using cif::Category; using cif::Category;
using cif::Row; using cif::Row;
...@@ -992,7 +989,7 @@ std::string Remark3Parser::nextLine() ...@@ -992,7 +989,7 @@ std::string Remark3Parser::nextLine()
while (mRec->is("REMARK 3") and mRec->mVlen > valueIndent) while (mRec->is("REMARK 3") and mRec->mVlen > valueIndent)
{ {
std::string v(mRec->mValue + 4, mRec->mValue + mRec->mVlen); std::string v(mRec->mValue + 4, mRec->mValue + mRec->mVlen);
if (not ba::starts_with(v, indent)) if (not cif::starts_with(v, indent))
break; break;
mLine += ' '; mLine += ' ';
...@@ -1146,7 +1143,7 @@ void Remark3Parser::storeCapture(const char* category, std::initializer_list<con ...@@ -1146,7 +1143,7 @@ void Remark3Parser::storeCapture(const char* category, std::initializer_list<con
++capture; ++capture;
std::string value = mM[capture].str(); std::string value = mM[capture].str();
ba::trim(value); cif::trim(value);
if (iequals(value, "NULL") or iequals(value, "NONE") or iequals(value, "Inf") or iequals(value, "+Inf") or iequals(value, std::string(value.length(), '*'))) if (iequals(value, "NULL") or iequals(value, "NONE") or iequals(value, "Inf") or iequals(value, "+Inf") or iequals(value, std::string(value.length(), '*')))
continue; continue;
...@@ -1253,7 +1250,7 @@ void Remark3Parser::storeRefineLsRestr(const char* type, std::initializer_list<c ...@@ -1253,7 +1250,7 @@ void Remark3Parser::storeRefineLsRestr(const char* type, std::initializer_list<c
++capture; ++capture;
std::string value = mM[capture].str(); std::string value = mM[capture].str();
ba::trim(value); cif::trim(value);
if (value.empty() or iequals(value, "NULL") or iequals(value, "Inf") or iequals(value, "+Inf") or iequals(value, std::string(value.length(), '*'))) if (value.empty() or iequals(value, "NULL") or iequals(value, "Inf") or iequals(value, "+Inf") or iequals(value, std::string(value.length(), '*')))
continue; continue;
...@@ -1284,7 +1281,7 @@ void Remark3Parser::updateRefineLsRestr(const char* type, std::initializer_list< ...@@ -1284,7 +1281,7 @@ void Remark3Parser::updateRefineLsRestr(const char* type, std::initializer_list<
++capture; ++capture;
std::string value = mM[capture].str(); std::string value = mM[capture].str();
ba::trim(value); cif::trim(value);
if (iequals(value, "NULL") or iequals(value, std::string(value.length(), '*'))) if (iequals(value, "NULL") or iequals(value, std::string(value.length(), '*')))
value.clear(); value.clear();
...@@ -1385,32 +1382,29 @@ bool Remark3Parser::parse(const std::string& expMethod, PDBRecord* r, cif::Datab ...@@ -1385,32 +1382,29 @@ bool Remark3Parser::parse(const std::string& expMethod, PDBRecord* r, cif::Datab
} }
}; };
for (auto p = make_split_iterator(line, ba::first_finder(", ")); for (auto program : cif::split<std::string>(line, ", ", true))
not p.eof(); ++p)
{ {
std::string program(p->begin(), p->end()); if (cif::starts_with(program, "BUSTER"))
if (ba::starts_with(program, "BUSTER"))
tryParser(new BUSTER_TNT_Remark3Parser(program, expMethod, r, db)); tryParser(new BUSTER_TNT_Remark3Parser(program, expMethod, r, db));
else if (ba::starts_with(program, "CNS") or ba::starts_with(program, "CNX")) else if (cif::starts_with(program, "CNS") or cif::starts_with(program, "CNX"))
tryParser(new CNS_Remark3Parser(program, expMethod, r, db)); tryParser(new CNS_Remark3Parser(program, expMethod, r, db));
else if (ba::starts_with(program, "PHENIX")) else if (cif::starts_with(program, "PHENIX"))
tryParser(new PHENIX_Remark3Parser(program, expMethod, r, db)); tryParser(new PHENIX_Remark3Parser(program, expMethod, r, db));
else if (ba::starts_with(program, "NUCLSQ")) else if (cif::starts_with(program, "NUCLSQ"))
tryParser(new NUCLSQ_Remark3Parser(program, expMethod, r, db)); tryParser(new NUCLSQ_Remark3Parser(program, expMethod, r, db));
else if (ba::starts_with(program, "PROLSQ")) else if (cif::starts_with(program, "PROLSQ"))
tryParser(new PROLSQ_Remark3Parser(program, expMethod, r, db)); tryParser(new PROLSQ_Remark3Parser(program, expMethod, r, db));
else if (ba::starts_with(program, "REFMAC")) else if (cif::starts_with(program, "REFMAC"))
{ {
// simply try both and take the best // simply try both and take the best
tryParser(new REFMAC_Remark3Parser(program, expMethod, r, db)); tryParser(new REFMAC_Remark3Parser(program, expMethod, r, db));
tryParser(new REFMAC5_Remark3Parser(program, expMethod, r, db)); tryParser(new REFMAC5_Remark3Parser(program, expMethod, r, db));
} }
else if (ba::starts_with(program, "SHELXL")) else if (cif::starts_with(program, "SHELXL"))
tryParser(new SHELXL_Remark3Parser(program, expMethod, r, db)); tryParser(new SHELXL_Remark3Parser(program, expMethod, r, db));
else if (ba::starts_with(program, "TNT")) else if (cif::starts_with(program, "TNT"))
tryParser(new TNT_Remark3Parser(program, expMethod, r, db)); tryParser(new TNT_Remark3Parser(program, expMethod, r, db));
else if (ba::starts_with(program, "X-PLOR")) else if (cif::starts_with(program, "X-PLOR"))
tryParser(new XPLOR_Remark3Parser(program, expMethod, r, db)); tryParser(new XPLOR_Remark3Parser(program, expMethod, r, db));
else if (cif::VERBOSE > 0) else if (cif::VERBOSE > 0)
std::cerr << "Skipping unknown program (" << program << ") in REMARK 3" << std::endl; std::cerr << "Skipping unknown program (" << program << ") in REMARK 3" << std::endl;
......
...@@ -30,13 +30,9 @@ ...@@ -30,13 +30,9 @@
#include <numeric> #include <numeric>
#include <thread> #include <thread>
#include <boost/algorithm/string.hpp>
#include <cif++/Secondary.hpp> #include <cif++/Secondary.hpp>
#include <cif++/Structure.hpp> #include <cif++/Structure.hpp>
namespace ba = boost::algorithm;
// -------------------------------------------------------------------- // --------------------------------------------------------------------
namespace mmcif namespace mmcif
...@@ -106,7 +102,7 @@ const ResidueInfo kResidueInfo[] = { ...@@ -106,7 +102,7 @@ const ResidueInfo kResidueInfo[] = {
ResidueType MapResidue(std::string inName) ResidueType MapResidue(std::string inName)
{ {
ba::trim(inName); cif::trim(inName);
ResidueType result = kUnknownResidue; ResidueType result = kUnknownResidue;
......
...@@ -31,9 +31,7 @@ ...@@ -31,9 +31,7 @@
#include <iomanip> #include <iomanip>
#include <numeric> #include <numeric>
#include <boost/algorithm/string.hpp> #include <gzstream/gzstream.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#if __cpp_lib_format #if __cpp_lib_format
#include <format> #include <format>
...@@ -47,8 +45,6 @@ ...@@ -47,8 +45,6 @@
// #include <cif++/AtomShape.hpp> // #include <cif++/AtomShape.hpp>
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace ba = boost::algorithm;
namespace io = boost::iostreams;
extern int cif::VERBOSE; extern int cif::VERBOSE;
...@@ -1289,81 +1285,27 @@ float Branch::weight() const ...@@ -1289,81 +1285,27 @@ float Branch::weight() const
void File::load(const std::filesystem::path &path) void File::load(const std::filesystem::path &path)
{ {
std::ifstream inFile(path, std::ios_base::in | std::ios_base::binary);
if (not inFile.is_open())
throw std::runtime_error("No such file: " + path.string());
io::filtering_stream<io::input> in;
std::string ext = path.extension().string(); std::string ext = path.extension().string();
if (path.extension() == ".gz") if (ext == ".gz")
{ {
in.push(io::gzip_decompressor()); gzstream::ifstream in(path);
ext = path.stem().extension().string();
}
in.push(inFile); ext = path.stem().extension().string();
try if (ext == ".pdb" or ext == ".ent")
{
// OK, we've got the file, now create a protein
if (ext == ".cif")
load(in);
else if (ext == ".pdb" or ext == ".ent")
ReadPDBFile(in, *this); ReadPDBFile(in, *this);
else else
{ cif::File::load(in);
try
{
if (cif::VERBOSE > 0)
std::cerr << "unrecognized file extension, trying cif" << std::endl;
cif::File::load(in);
}
catch (const cif::CifParserError &e)
{
if (cif::VERBOSE > 0)
std::cerr << "Not cif, trying plain old PDB" << std::endl;
// pffft...
in.reset();
if (inFile.is_open())
inFile.seekg(0);
else
inFile.open(path, std::ios_base::in | std::ios::binary);
if (path.extension() == ".gz")
in.push(io::gzip_decompressor());
in.push(inFile);
ReadPDBFile(in, *this);
}
}
} }
catch (const std::exception &ex) else
{ {
if (cif::VERBOSE >= 0) std::ifstream in(path, std::ios_base::binary);
std::cerr << "Error trying to load file " << path << std::endl;
throw;
}
// validate, otherwise lots of functionality won't work
loadDictionary("mmcif_pdbx_v50");
if (not isValid() and cif::VERBOSE >= 0)
std::cerr << "Invalid mmCIF file" << (cif::VERBOSE > 0 ? "." : " use --verbose option to see errors") << std::endl;
}
void File::load(std::istream &is) if (ext == ".pdb" or ext == ".ent")
{ ReadPDBFile(in, *this);
try else
{ cif::File::load(in);
cif::File::load(is);
}
catch (const cif::CifParserError &e)
{
ReadPDBFile(is, *this);
} }
// validate, otherwise lots of functionality won't work // validate, otherwise lots of functionality won't work
...@@ -1376,21 +1318,20 @@ void File::save(const std::filesystem::path &path) ...@@ -1376,21 +1318,20 @@ void File::save(const std::filesystem::path &path)
{ {
fs::path file = path.filename(); fs::path file = path.filename();
std::ofstream outFile(path, std::ios_base::out | std::ios_base::binary); std::unique_ptr<std::ostream> outFile;
io::filtering_stream<io::output> out;
if (file.extension() == ".gz") if (file.extension() == ".gz")
{ {
out.push(io::gzip_compressor()); outFile.reset(new gzstream::ofstream(path));
file.replace_extension(""); file.replace_extension("");
} }
else
out.push(outFile); outFile.reset(new std::ofstream(path, std::ios_base::out | std::ios_base::binary));
if (file.extension() == ".pdb") if (file.extension() == ".pdb")
WritePDBFile(out, data()); WritePDBFile(*outFile, data());
else else
cif::File::save(out); cif::File::save(*outFile);
} }
// -------------------------------------------------------------------- // --------------------------------------------------------------------
......
...@@ -24,12 +24,8 @@ ...@@ -24,12 +24,8 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <boost/algorithm/string.hpp>
#include <cif++/TlsParser.hpp> #include <cif++/TlsParser.hpp>
namespace ba = boost::algorithm;
namespace cif namespace cif
{ {
...@@ -1830,7 +1826,7 @@ TLSSelectionPtr ParseSelectionDetails(const std::string& program, const std::str ...@@ -1830,7 +1826,7 @@ TLSSelectionPtr ParseSelectionDetails(const std::string& program, const std::str
TLSSelectionPtr result; TLSSelectionPtr result;
if (ba::icontains(program, "buster")) if (cif::icontains(program, "buster"))
{ {
result = buster.Parse(selection); result = buster.Parse(selection);
...@@ -1848,7 +1844,7 @@ TLSSelectionPtr ParseSelectionDetails(const std::string& program, const std::str ...@@ -1848,7 +1844,7 @@ TLSSelectionPtr ParseSelectionDetails(const std::string& program, const std::str
result = phenix.Parse(selection); result = phenix.Parse(selection);
} }
} }
else if (ba::icontains(program, "phenix")) else if (cif::icontains(program, "phenix"))
{ {
result = phenix.Parse(selection); result = phenix.Parse(selection);
......
...@@ -1294,9 +1294,9 @@ bool DictParser::collectItemTypes() ...@@ -1294,9 +1294,9 @@ bool DictParser::collectItemTypes()
std::string code, primitiveCode, construct; std::string code, primitiveCode, construct;
cif::tie(code, primitiveCode, construct) = t.get("code", "primitive_code", "construct"); cif::tie(code, primitiveCode, construct) = t.get("code", "primitive_code", "construct");
ba::replace_all(construct, "\\n", "\n"); cif::replace_all(construct, "\\n", "\n");
ba::replace_all(construct, "\\t", "\t"); cif::replace_all(construct, "\\t", "\t");
ba::replace_all(construct, "\\\n", ""); cif::replace_all(construct, "\\\n", "");
try try
{ {
......
...@@ -34,32 +34,6 @@ ...@@ -34,32 +34,6 @@
namespace cif::v2 namespace cif::v2
{ {
template <typename V>
std::string join(const V &arr, std::string_view sep)
{
std::ostringstream s;
if (not arr.empty())
{
auto ai = arr.begin();
auto ni = std::next(ai);
for (;;)
{
s << *ai;
ai = ni;
ni = std::next(ai);
if (ni == arr.end())
break;
s << sep;
}
}
return s.str();
}
// -------------------------------------------------------------------- // --------------------------------------------------------------------
class row_comparator class row_comparator
...@@ -1013,8 +987,13 @@ category::iterator category::erase(iterator pos) ...@@ -1013,8 +987,13 @@ category::iterator category::erase(iterator pos)
for (size_t ix = 0; ix < link->m_parent_keys.size(); ++ix) for (size_t ix = 0; ix < link->m_parent_keys.size(); ++ix)
{ {
std::string_view value = rh[link->m_parent_keys[ix]].text(); std::string_view value = rh[link->m_parent_keys[ix]].text();
// cond = std::move(cond) and (key(link->m_child_keys[ix]) == value or key(link->m_child_keys[ix]) == null);
cond = std::move(cond) and (key(link->m_child_keys[ix]) == value); auto childKey = link->m_child_keys[ix];
if (childCat->m_cat_validator and childCat->m_cat_validator->m_mandatory_fields.contains(childKey))
cond = std::move(cond) and key(childKey) == value;
else
cond = std::move(cond) and (key(childKey) == value or key(childKey) == null);
} }
childCat->erase_orphans(std::move(cond)); childCat->erase_orphans(std::move(cond));
...@@ -1133,6 +1112,164 @@ void category::erase_orphans(condition &&cond) ...@@ -1133,6 +1112,164 @@ void category::erase_orphans(condition &&cond)
erase(iterator(*this, r)); erase(iterator(*this, r));
} }
std::string category::get_unique_id(std::function<std::string(int)> generator)
{
using namespace cif::v2::literals;
std::string id_tag = "id";
if (m_cat_validator != nullptr and m_cat_validator->m_keys.size() == 1)
id_tag = m_cat_validator->m_keys.front();
// calling size() often is a waste of resources
if (m_last_unique_num == 0)
m_last_unique_num = size();
for (;;)
{
std::string result = generator(static_cast<int>(m_last_unique_num++));
if (exists(key(id_tag) == result))
continue;
return result;
}
}
void category::update_value(const std::vector<row_handle> &rows, std::string_view tag, std::string_view value)
{
using namespace std::literals;
if (rows.empty())
return;
auto colIx = get_column_ix(tag);
if (colIx >= m_columns.size())
throw std::runtime_error("Invalid column " + std::string{ value } + " for " + m_name);
auto &col = m_columns[colIx];
// check the value
if (col.m_validator)
(*col.m_validator)(value);
// first some sanity checks, what was the old value and is it the same for all rows?
std::string_view oldValue = rows.front()[tag].text();
for (auto row : rows)
{
if (oldValue != row[tag].text())
throw std::runtime_error("Inconsistent old values in update_value");
}
if (oldValue == value) // no need to do anything
return;
// update rows, but do not cascade
for (auto row : rows)
row.assign(colIx, value, false);
// see if we need to update any child categories that depend on this value
for (auto parent : rows)
{
for (auto &&[childCat, linked] : m_child_links)
{
if (std::find(linked->m_parent_keys.begin(), linked->m_parent_keys.end(), tag) == linked->m_parent_keys.end())
continue;
condition cond;
std::string childTag;
for (size_t ix = 0; ix < linked->m_parent_keys.size(); ++ix)
{
std::string pk = linked->m_parent_keys[ix];
std::string ck = linked->m_child_keys[ix];
// TODO: add code to *NOT* test mandatory fields for Empty
if (pk == tag)
{
childTag = ck;
cond = std::move(cond) && key(ck) == oldValue;
}
else
cond = std::move(cond) && key(ck) == parent[pk].text();
}
auto children = childCat->find(std::move(cond));
if (children.empty())
continue;
std::vector<row_handle> child_rows;
std::copy(children.begin(), children.end(), std::back_inserter(child_rows));
// now be careful. If we search back from child to parent and still find a valid parent row
// we cannot simply rename the child but will have to create a new child. Unless that new
// child already exists of course.
std::vector<row_handle> process;
for (auto child : child_rows)
{
condition cond_c;
for (size_t ix = 0; ix < linked->m_parent_keys.size(); ++ix)
{
std::string pk = linked->m_parent_keys[ix];
std::string ck = linked->m_child_keys[ix];
// TODO: add code to *NOT* test mandatory fields for Empty
cond_c = std::move(cond_c) && key(pk) == child[ck].text();
}
auto parents = find(std::move(cond_c));
if (parents.empty())
{
process.push_back(child);
continue;
}
// oops, we need to split this child, unless a row already exists for the new value
condition check;
for (size_t ix = 0; ix < linked->m_parent_keys.size(); ++ix)
{
std::string pk = linked->m_parent_keys[ix];
std::string ck = linked->m_child_keys[ix];
// TODO: add code to *NOT* test mandatory fields for Empty
if (pk == tag)
check = std::move(check) && key(ck) == value;
else
check = std::move(check) && key(ck) == parent[pk].text();
}
if (childCat->exists(std::move(check))) // phew..., narrow escape
continue;
// create the actual copy, if we can...
if (childCat->m_cat_validator != nullptr and childCat->m_cat_validator->m_keys.size() == 1)
{
auto copy = childCat->create_copy(child);
if (copy != child)
{
process.push_back(child);
continue;
}
}
// cannot update this...
if (cif::VERBOSE > 0)
std::cerr << "Cannot update child " << childCat->m_name << "." << childTag << " with value " << value << std::endl;
}
// finally, update the children
if (not process.empty())
childCat->update_value(std::move(process), childTag, value);
}
}
}
void category::update_value(row *row, size_t column, std::string_view value, bool updateLinked, bool validate) void category::update_value(row *row, size_t column, std::string_view value, bool updateLinked, bool validate)
{ {
auto &col = m_columns[column]; auto &col = m_columns[column];
...@@ -1235,7 +1372,7 @@ void category::update_value(row *row, size_t column, std::string_view value, boo ...@@ -1235,7 +1372,7 @@ void category::update_value(row *row, size_t column, std::string_view value, boo
std::string pk = linked->m_parent_keys[ix]; std::string pk = linked->m_parent_keys[ix];
std::string ck = linked->m_child_keys[ix]; std::string ck = linked->m_child_keys[ix];
// TODO add code to *NOT* test mandatory fields for Empty // TODO: add code to *NOT* test mandatory fields for Empty
if (pk == iv->m_tag) if (pk == iv->m_tag)
{ {
...@@ -1272,7 +1409,7 @@ void category::update_value(row *row, size_t column, std::string_view value, boo ...@@ -1272,7 +1409,7 @@ void category::update_value(row *row, size_t column, std::string_view value, boo
std::string pk = linked->m_parent_keys[ix]; std::string pk = linked->m_parent_keys[ix];
std::string ck = linked->m_child_keys[ix]; std::string ck = linked->m_child_keys[ix];
// TODO add code to *NOT* test mandatory fields for Empty // TODO: add code to *NOT* test mandatory fields for Empty
if (pk == iv->m_tag) if (pk == iv->m_tag)
cond_n = std::move(cond_n) and key(ck) == value; cond_n = std::move(cond_n) and key(ck) == value;
...@@ -1301,6 +1438,40 @@ void category::update_value(row *row, size_t column, std::string_view value, boo ...@@ -1301,6 +1438,40 @@ void category::update_value(row *row, size_t column, std::string_view value, boo
} }
} }
row_handle category::create_copy(row_handle r)
{
// copy the values
std::vector<item> items;
for (item_value *iv = r.m_row->m_head; iv != nullptr; iv = iv->m_next)
items.emplace_back(m_columns[iv->m_column_ix].m_name, iv->text());
if (m_cat_validator and m_cat_validator->m_keys.size() == 1)
{
auto key = m_cat_validator->m_keys.front();
auto kv = m_cat_validator->get_validator_for_item(key);
for (auto &item : items)
{
if (item.name() != key)
continue;
if (kv->m_type->m_primitive_type == DDL_PrimitiveType::Numb)
item.value(get_unique_id(""));
else
item.value(get_unique_id(m_name + "_id_"));
break;
}
}
return emplace(items.begin(), items.end());
// auto &&[result, inserted] = emplace(items.begin(), items.end());
// // assert(inserted);
// return result;
}
// proxy methods for every insertion // proxy methods for every insertion
category::iterator category::insert_impl(const_iterator pos, row *n) category::iterator category::insert_impl(const_iterator pos, row *n)
{ {
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <gzstream/gzstream.hpp>
#include <cif++/v2/dictionary_parser.hpp> #include <cif++/v2/dictionary_parser.hpp>
#include <cif++/v2/validate.hpp> #include <cif++/v2/validate.hpp>
...@@ -407,13 +409,10 @@ const validator &validator_factory::operator[](std::string_view dictionary_name) ...@@ -407,13 +409,10 @@ const validator &validator_factory::operator[](std::string_view dictionary_name)
if (std::filesystem::exists(p, ec) and not ec) if (std::filesystem::exists(p, ec) and not ec)
{ {
std::ifstream file(p, std::ios::binary); gzstream::ifstream in(p);
if (not file.is_open())
throw std::runtime_error("Could not open dictionary (" + p.string() + ")");
io::filtering_stream<io::input> in; if (not in.is_open())
in.push(io::gzip_decompressor()); throw std::runtime_error("Could not open dictionary (" + p.string() + ")");
in.push(file);
construct_validator(dictionary_name, in); construct_validator(dictionary_name, in);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment