Commit 7dd6a8a1 by Maarten L. Hekkelman

fixes and updated submodules

parent 96725ae8
[submodule "regex"] [submodule "regex"]
path = regex path = regex
url = https://github.com/boostorg/regex url = https://github.com/boostorg/regex
[submodule "gxrio"]
path = gxrio
url = https://github.com/mhekkel/gxrio.git
...@@ -94,6 +94,7 @@ endif() ...@@ -94,6 +94,7 @@ endif()
# Start by finding out if std:regex is usable. Note that the current # Start by finding out if std:regex is usable. Note that the current
# implementation in GCC is not acceptable, it crashes on long lines. # implementation in GCC is not acceptable, it crashes on long lines.
# The implementation in libc++ (clang) and MSVC seem to be OK.
check_cxx_source_compiles(" check_cxx_source_compiles("
#include <iostream> #include <iostream>
#ifndef __GLIBCXX__ #ifndef __GLIBCXX__
...@@ -119,7 +120,7 @@ set(CMAKE_THREAD_PREFER_PTHREAD) ...@@ -119,7 +120,7 @@ set(CMAKE_THREAD_PREFER_PTHREAD)
set(THREADS_PREFER_PTHREAD_FLAG) set(THREADS_PREFER_PTHREAD_FLAG)
find_package(Threads) find_package(Threads)
find_package(gxrio REQUIRED) add_git_submodule(gxrio EXCLUDE_FROM_ALL)
include(FindFilesystem) include(FindFilesystem)
list(APPEND CIFPP_REQUIRED_LIBRARIES ${STDCPPFS_LIBRARY}) list(APPEND CIFPP_REQUIRED_LIBRARIES ${STDCPPFS_LIBRARY})
...@@ -315,9 +316,9 @@ file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/libcifpp.pc ...@@ -315,9 +316,9 @@ 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(ENABLE_TESTING "Build test exectuables" OFF)
if(CIFPP_BUILD_TESTS) if(ENABLE_TESTING)
enable_testing() enable_testing()
find_package(Boost REQUIRED) find_package(Boost REQUIRED)
......
...@@ -16,5 +16,7 @@ function(add_git_submodule dir) ...@@ -16,5 +16,7 @@ function(add_git_submodule dir)
COMMAND_ERROR_IS_FATAL ANY) COMMAND_ERROR_IS_FATAL ANY)
endif() endif()
set(ENABLE_TESTING OFF)
add_subdirectory(${dir} ${ARGV}) add_subdirectory(${dir} ${ARGV})
endfunction(add_git_submodule) endfunction(add_git_submodule)
\ No newline at end of file
Subproject commit 4587355dd281665f7d489360553d2f7564f398e4
...@@ -72,7 +72,10 @@ class item ...@@ -72,7 +72,10 @@ class item
item(std::string_view name, const T &value, int precision) item(std::string_view name, const T &value, int precision)
: m_name(name) : m_name(name)
{ {
auto r = cif::to_chars(m_buffer, m_buffer + sizeof(m_buffer) - 1, value, cif::chars_format::fixed, precision); using namespace std;
using namespace cif;
auto r = to_chars(m_buffer, m_buffer + sizeof(m_buffer) - 1, value, chars_format::fixed, precision);
if (r.ec != std::errc()) if (r.ec != std::errc())
throw std::runtime_error("Could not format number"); throw std::runtime_error("Could not format number");
...@@ -88,7 +91,10 @@ class item ...@@ -88,7 +91,10 @@ class item
item(const std::string_view name, const T &value) item(const std::string_view name, const T &value)
: m_name(name) : m_name(name)
{ {
auto r = cif::to_chars(m_buffer, m_buffer + sizeof(m_buffer) - 1, value, cif::chars_format::general); using namespace std;
using namespace cif;
auto r = to_chars(m_buffer, m_buffer + sizeof(m_buffer) - 1, value, chars_format::general);
if (r.ec != std::errc()) if (r.ec != std::errc())
throw std::runtime_error("Could not format number"); throw std::runtime_error("Could not format number");
...@@ -303,7 +309,7 @@ struct item_handle ...@@ -303,7 +309,7 @@ struct item_handle
void assign_value(const item &value); void assign_value(const item &value);
}; };
// So sad that the gcc implementation of from_chars does not support floats yet... // So sad that older gcc implementations of from_chars did not support floats yet...
template <typename T> template <typename T>
struct item_handle::item_value_as<T, std::enable_if_t<std::is_arithmetic_v<T> and not std::is_same_v<T, bool>>> struct item_handle::item_value_as<T, std::enable_if_t<std::is_arithmetic_v<T> and not std::is_same_v<T, bool>>>
...@@ -316,12 +322,7 @@ struct item_handle::item_value_as<T, std::enable_if_t<std::is_arithmetic_v<T> an ...@@ -316,12 +322,7 @@ struct item_handle::item_value_as<T, std::enable_if_t<std::is_arithmetic_v<T> an
value_type result = {}; value_type result = {};
std::from_chars_result r; std::from_chars_result r = selected_charconv<value_type>::from_chars(txt.data(), txt.data() + txt.size(), result);
if constexpr (std::is_floating_point_v<T>)
r = cif::from_chars(txt.data(), txt.data() + txt.size(), result);
else
r = std::from_chars(txt.data(), txt.data() + txt.size(), result);
if (r.ec != std::errc()) if (r.ec != std::errc())
{ {
...@@ -350,12 +351,7 @@ struct item_handle::item_value_as<T, std::enable_if_t<std::is_arithmetic_v<T> an ...@@ -350,12 +351,7 @@ struct item_handle::item_value_as<T, std::enable_if_t<std::is_arithmetic_v<T> an
{ {
value_type v = {}; value_type v = {};
std::from_chars_result r; std::from_chars_result r = selected_charconv<value_type>::from_chars(txt.data(), txt.data() + txt.size(), v);
if constexpr (std::is_floating_point_v<T>)
r = cif::from_chars(txt.data(), txt.data() + txt.size(), v);
else
r = std::from_chars(txt.data(), txt.data() + txt.size(), v);
if (r.ec != std::errc()) if (r.ec != std::errc())
{ {
......
...@@ -33,6 +33,10 @@ ...@@ -33,6 +33,10 @@
#include <tuple> #include <tuple>
#include <vector> #include <vector>
#if __has_include(<experimental/type_traits>)
#include <experimental/type_traits>
#endif
namespace cif namespace cif
{ {
...@@ -205,13 +209,18 @@ std::vector<std::string> word_wrap(const std::string &text, size_t width); ...@@ -205,13 +209,18 @@ std::vector<std::string> word_wrap(const std::string &text, size_t width);
// -------------------------------------------------------------------- // --------------------------------------------------------------------
/// std::from_chars for floating point types. /// std::from_chars for floating point types.
/// These are optional, there's a selected_charconv class below that selects
/// the best option to used based on support by the stl library
/// I.e. that in case of GNU < 12 (or something) the cif implementation will
/// be used, all other cases will use the stl version.
template <typename FloatType, std::enable_if_t<std::is_floating_point_v<FloatType>, int> = 0> template <typename FloatType, std::enable_if_t<std::is_floating_point_v<FloatType>, int> = 0>
std::from_chars_result from_chars(const char *first, const char *last, FloatType &value) std::from_chars_result from_chars(const char *first, const char *last, FloatType &value)
{ {
std::from_chars_result result{first, {}}; std::from_chars_result result{ first, {} };
enum State { enum State
{
IntegerSign, IntegerSign,
Integer, Integer,
Fraction, Fraction,
...@@ -250,7 +259,7 @@ std::from_chars_result from_chars(const char *first, const char *last, FloatType ...@@ -250,7 +259,7 @@ std::from_chars_result from_chars(const char *first, const char *last, FloatType
else else
result.ec = std::errc::invalid_argument; result.ec = std::errc::invalid_argument;
break; break;
case Integer: case Integer:
if (ch >= '0' and ch <= '9') if (ch >= '0' and ch <= '9')
vi = 10 * vi + (ch - '0'); vi = 10 * vi + (ch - '0');
...@@ -264,7 +273,7 @@ std::from_chars_result from_chars(const char *first, const char *last, FloatType ...@@ -264,7 +273,7 @@ std::from_chars_result from_chars(const char *first, const char *last, FloatType
--result.ptr; --result.ptr;
} }
break; break;
case Fraction: case Fraction:
if (ch >= '0' and ch <= '9') if (ch >= '0' and ch <= '9')
{ {
...@@ -296,7 +305,7 @@ std::from_chars_result from_chars(const char *first, const char *last, FloatType ...@@ -296,7 +305,7 @@ std::from_chars_result from_chars(const char *first, const char *last, FloatType
else else
result.ec = std::errc::invalid_argument; result.ec = std::errc::invalid_argument;
break; break;
case Exponent: case Exponent:
if (ch >= '0' and ch <= '9') if (ch >= '0' and ch <= '9')
exponent = 10 * exponent + (ch - '0'); exponent = 10 * exponent + (ch - '0');
...@@ -328,10 +337,10 @@ std::from_chars_result from_chars(const char *first, const char *last, FloatType ...@@ -328,10 +337,10 @@ std::from_chars_result from_chars(const char *first, const char *last, FloatType
enum class chars_format enum class chars_format
{ {
scientific = 1, scientific = 1,
fixed = 2, fixed = 2,
// hex, // hex,
general = fixed | scientific general = fixed | scientific
}; };
template <typename FloatType, std::enable_if_t<std::is_floating_point_v<FloatType>, int> = 0> template <typename FloatType, std::enable_if_t<std::is_floating_point_v<FloatType>, int> = 0>
...@@ -412,5 +421,38 @@ std::to_chars_result to_chars(char *first, char *last, FloatType &value, chars_f ...@@ -412,5 +421,38 @@ std::to_chars_result to_chars(char *first, char *last, FloatType &value, chars_f
return result; return result;
} }
template <typename T>
struct my_charconv
{
static std::from_chars_result from_chars(const char *a, const char *b, T &d)
{
return cif::from_chars(a, b, d);
}
static std::to_chars_result to_chars(char *first, char *last, T &value, chars_format fmt)
{
return cif::to_chars(first, last, value, fmt);
}
};
template <typename T>
struct std_charconv
{
static std::from_chars_result from_chars(const char *a, const char *b, T &d)
{
return std::from_chars(a, b, d);
}
static std::to_chars_result to_chars(char *first, char *last, T &value, chars_format fmt)
{
return std::to_chars(first, last, value, fmt);
}
};
template <typename T>
using from_chars_function = decltype(std::from_chars(std::declval<const char *>(), std::declval<const char *>(), std::declval<T &>()));
template <typename T>
using selected_charconv = typename std::conditional_t<std::experimental::is_detected_v<from_chars_function, T>, std_charconv<T>, my_charconv<T>>;
} // namespace cif } // namespace cif
\ No newline at end of file
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
// The validator depends on regular expressions. Unfortunately, // The validator depends on regular expressions. Unfortunately,
// the implementation of std::regex in g++ is buggy and crashes // the implementation of std::regex in g++ is buggy and crashes
// on reading the pdbx dictionary. Therefore, in case g++ is used // on reading the pdbx dictionary. Therefore, in case g++ is used
// the code will use boost::regex instead. // the code will use boost::regex instead.
#if USE_BOOST_REGEX #if USE_BOOST_REGEX
#include <boost/regex.hpp> #include <boost/regex.hpp>
...@@ -90,7 +90,7 @@ DDL_PrimitiveType map_to_primitive_type(std::string_view s) ...@@ -90,7 +90,7 @@ DDL_PrimitiveType map_to_primitive_type(std::string_view s)
type_validator::type_validator(std::string_view name, DDL_PrimitiveType type, std::string_view rx) type_validator::type_validator(std::string_view name, DDL_PrimitiveType type, std::string_view rx)
: m_name(name) : m_name(name)
, m_primitive_type(type) , m_primitive_type(type)
, m_rx(new regex_impl(rx.empty() ? ".+" : rx)) /// Empty regular expressions are not allowed, in libcpp's std::regex (POSIX?) , m_rx(new regex_impl(rx.empty() ? ".+" : rx)) /// Empty regular expressions are not allowed, in libcpp's std::regex (POSIX?)
{ {
} }
...@@ -99,6 +99,24 @@ type_validator::~type_validator() ...@@ -99,6 +99,24 @@ type_validator::~type_validator()
delete m_rx; delete m_rx;
} }
template <typename T>
struct my_from_chars
{
static std::from_chars_result from_chars(const char *a, const char *b, T &d)
{
return cif::from_chars(a, b, d);
}
};
template <typename T>
struct std_from_chars
{
static std::from_chars_result from_chars(const char *a, const char *b, T &d)
{
return std::from_chars(a, b, d);
}
};
int type_validator::compare(std::string_view a, std::string_view b) const int type_validator::compare(std::string_view a, std::string_view b) const
{ {
int result = 0; int result = 0;
...@@ -115,8 +133,13 @@ int type_validator::compare(std::string_view a, std::string_view b) const ...@@ -115,8 +133,13 @@ int type_validator::compare(std::string_view a, std::string_view b) const
{ {
double da, db; double da, db;
auto ra = cif::from_chars(a.begin(), a.end(), da); using namespace cif;
auto rb = cif::from_chars(b.begin(), b.end(), db); using namespace std;
std::from_chars_result ra, rb;
ra = selected_charconv<double>::from_chars(a.begin(), a.end(), da);
rb = selected_charconv<double>::from_chars(b.begin(), b.end(), db);
if (ra.ec == std::errc() and rb.ec == std::errc()) if (ra.ec == std::errc() and rb.ec == std::errc())
{ {
...@@ -218,12 +241,12 @@ void item_validator::operator()(std::string_view value) const ...@@ -218,12 +241,12 @@ void item_validator::operator()(std::string_view value) const
if (not value.empty() and value != "?" and value != ".") if (not value.empty() and value != "?" and value != ".")
{ {
if (m_type != nullptr and not regex_match(value.begin(), value.end(), *m_type->m_rx)) if (m_type != nullptr and not regex_match(value.begin(), value.end(), *m_type->m_rx))
throw validation_error(m_category->m_name, m_tag, "Value '" + std::string{value} + "' does not match type expression for type " + m_type->m_name); throw validation_error(m_category->m_name, m_tag, "Value '" + std::string{ value } + "' does not match type expression for type " + m_type->m_name);
if (not m_enums.empty()) if (not m_enums.empty())
{ {
if (m_enums.count(std::string{value}) == 0) if (m_enums.count(std::string{ value }) == 0)
throw validation_error(m_category->m_name, m_tag, "Value '" + std::string{value} + "' is not in the list of allowed values"); throw validation_error(m_category->m_name, m_tag, "Value '" + std::string{ value } + "' is not in the list of allowed values");
} }
} }
} }
...@@ -245,7 +268,7 @@ void category_validator::addItemValidator(item_validator &&v) ...@@ -245,7 +268,7 @@ void category_validator::addItemValidator(item_validator &&v)
const item_validator *category_validator::get_validator_for_item(std::string_view tag) const const item_validator *category_validator::get_validator_for_item(std::string_view tag) const
{ {
const item_validator *result = nullptr; const item_validator *result = nullptr;
auto i = m_item_validators.find(item_validator{std::string(tag)}); auto i = m_item_validators.find(item_validator{ std::string(tag) });
if (i != m_item_validators.end()) if (i != m_item_validators.end())
result = &*i; result = &*i;
else if (VERBOSE > 4) else if (VERBOSE > 4)
...@@ -266,7 +289,7 @@ const type_validator *validator::get_validator_for_type(std::string_view typeCod ...@@ -266,7 +289,7 @@ const type_validator *validator::get_validator_for_type(std::string_view typeCod
{ {
const type_validator *result = nullptr; const type_validator *result = nullptr;
auto i = m_type_validators.find(type_validator{std::string(typeCode), DDL_PrimitiveType::Char, {}}); auto i = m_type_validators.find(type_validator{ std::string(typeCode), DDL_PrimitiveType::Char, {} });
if (i != m_type_validators.end()) if (i != m_type_validators.end())
result = &*i; result = &*i;
else if (VERBOSE > 4) else if (VERBOSE > 4)
...@@ -284,7 +307,7 @@ void validator::add_category_validator(category_validator &&v) ...@@ -284,7 +307,7 @@ void validator::add_category_validator(category_validator &&v)
const category_validator *validator::get_validator_for_category(std::string_view category) const const category_validator *validator::get_validator_for_category(std::string_view category) const
{ {
const category_validator *result = nullptr; const category_validator *result = nullptr;
auto i = m_category_validators.find(category_validator{std::string(category)}); auto i = m_category_validators.find(category_validator{ std::string(category) });
if (i != m_category_validators.end()) if (i != m_category_validators.end())
result = &*i; result = &*i;
else if (VERBOSE > 4) else if (VERBOSE > 4)
......
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