mirror of
https://github.com/PDB-REDO/libcifpp.git
synced 2026-06-04 13:54:25 +08:00
backup
This commit is contained in:
@@ -249,28 +249,28 @@ write_version_header("${CMAKE_CURRENT_SOURCE_DIR}/src/" LIB_NAME "LibCIFPP")
|
||||
# Sources
|
||||
set(project_sources
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/category.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/condition.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/datablock.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/dictionary_parser.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/file.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/condition.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/datablock.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/dictionary_parser.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/file.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/item.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/parser.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/row.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/validate.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/validate.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/text.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/utilities.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/atom_type.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/compound.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/point.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/symmetry.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/model.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/cif2pdb.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/pdb2cif.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/pdb_record.hpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/pdb2cif_remark_3.hpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/pdb2cif_remark_3.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/reconstruct.cpp
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/validate-pdbx.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/atom_type.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/compound.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/point.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/symmetry.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/model.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/cif2pdb.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/pdb2cif.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/pdb_record.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/pdb2cif_remark_3.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/pdb2cif_remark_3.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/reconstruct.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/pdb/validate-pdbx.cpp
|
||||
)
|
||||
|
||||
set(project_headers
|
||||
|
||||
@@ -124,16 +124,6 @@ class multiple_results_error : public std::runtime_error
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// These should be moved elsewhere, one day.
|
||||
|
||||
/// \cond
|
||||
template <typename T>
|
||||
inline constexpr bool is_optional_v = false;
|
||||
template <typename T>
|
||||
inline constexpr bool is_optional_v<std::optional<T>> = true;
|
||||
/// \endcond
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// The class category is a sequence container for rows of data values.
|
||||
@@ -154,8 +144,8 @@ class category
|
||||
friend class iterator_impl_base;
|
||||
|
||||
using value_type = row_handle;
|
||||
using reference = value_type;
|
||||
using const_reference = const value_type;
|
||||
using reference = row_handle;
|
||||
using const_reference = const_row_handle;
|
||||
using iterator = iterator_impl<>;
|
||||
using const_iterator = const_iterator_impl<>;
|
||||
|
||||
@@ -296,7 +286,7 @@ class category
|
||||
/// the category is empty.
|
||||
[[nodiscard]] const_reference front() const
|
||||
{
|
||||
return { const_cast<category &>(*this), const_cast<row &>(*m_head) };
|
||||
return { *this, *m_head };
|
||||
}
|
||||
|
||||
/// @brief Return a reference to the last row in this category.
|
||||
@@ -312,7 +302,7 @@ class category
|
||||
/// the category is empty.
|
||||
[[nodiscard]] const_reference back() const
|
||||
{
|
||||
return { const_cast<category &>(*this), const_cast<row &>(*m_tail) };
|
||||
return { *this, *m_tail };
|
||||
}
|
||||
|
||||
/// Return an iterator to the first row
|
||||
@@ -376,7 +366,7 @@ class category
|
||||
struct key_element_type
|
||||
{
|
||||
std::string name; ///< Name of the item
|
||||
std::string value; ///< Value to be found
|
||||
item_value value; ///< Value to be found
|
||||
bool may_be_null = false; ///< If true, value should be same or empty
|
||||
};
|
||||
|
||||
@@ -388,13 +378,10 @@ class category
|
||||
/// @return The row found in the index, or an undefined row_handle
|
||||
row_handle operator[](const key_type &key);
|
||||
|
||||
/// @brief Return a const row_handle for the row specified by \a key
|
||||
/// @brief Return a const_row_handle for the row specified by \a key
|
||||
/// @param key The value for the key, items specified in the dictionary should have a value
|
||||
/// @return The row found in the index, or an undefined row_handle
|
||||
const row_handle operator[](const key_type &key) const
|
||||
{
|
||||
return const_cast<category *>(this)->operator[](key);
|
||||
}
|
||||
const_row_handle operator[](const key_type &key) const;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
@@ -592,7 +579,7 @@ class category
|
||||
/// there are is not exactly one row matching @a cond
|
||||
/// @param cond The condition to search for
|
||||
/// @return Row handle to the row found
|
||||
const row_handle find1(condition &&cond) const
|
||||
const_row_handle find1(condition &&cond) const
|
||||
{
|
||||
return find1(cbegin(), std::move(cond));
|
||||
}
|
||||
@@ -602,7 +589,7 @@ class category
|
||||
/// @param pos The position to start the search
|
||||
/// @param cond The condition to search for
|
||||
/// @return Row handle to the row found
|
||||
const row_handle find1(const_iterator pos, condition &&cond) const
|
||||
const_row_handle find1(const_iterator pos, condition &&cond) const
|
||||
{
|
||||
auto h = find(pos, std::move(cond));
|
||||
|
||||
@@ -727,7 +714,7 @@ class category
|
||||
/// @brief Return a const row handle to the first row that matches @a cond
|
||||
/// @param cond The condition to search for
|
||||
/// @return The const handle to the row that matches or an empty row_handle
|
||||
const row_handle find_first(condition &&cond) const
|
||||
const_row_handle find_first(condition &&cond) const
|
||||
{
|
||||
return find_first(cbegin(), std::move(cond));
|
||||
}
|
||||
@@ -736,11 +723,11 @@ class category
|
||||
/// @param pos The location to start searching
|
||||
/// @param cond The condition to search for
|
||||
/// @return The const handle to the row that matches or an empty row_handle
|
||||
const row_handle find_first(const_iterator pos, condition &&cond) const
|
||||
const_row_handle find_first(const_iterator pos, condition &&cond) const
|
||||
{
|
||||
auto h = find(pos, std::move(cond));
|
||||
|
||||
return h.empty() ? row_handle{} : *h.begin();
|
||||
return h.empty() ? const_row_handle{} : *h.begin();
|
||||
}
|
||||
|
||||
/// @brief Return the value for item @a item for the first row that matches condition @a cond
|
||||
@@ -1041,7 +1028,7 @@ class category
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
using value_provider_type = std::function<std::string_view(std::string_view)>;
|
||||
using value_provider_type = std::function<item_value(const item_value &)>;
|
||||
|
||||
/// \brief Update a single item named @a item_name in the rows that match
|
||||
/// \a cond to values provided by a callback function \a value_provider
|
||||
@@ -1073,7 +1060,7 @@ class category
|
||||
/// That means, child categories are updated if the links are absolute
|
||||
/// and unique. If they are not, the child category rows are split.
|
||||
|
||||
void update_value(condition &&cond, std::string_view item_name, std::string_view value)
|
||||
void update_value(condition &&cond, std::string_view item_name, const item_value &value)
|
||||
{
|
||||
auto rs = find(std::move(cond));
|
||||
std::vector<row_handle> rows;
|
||||
@@ -1087,9 +1074,9 @@ class category
|
||||
/// That means, child categories are updated if the links are absolute
|
||||
/// and unique. If they are not, the child category rows are split.
|
||||
|
||||
void update_value(const std::vector<row_handle> &rows, std::string_view item_name, std::string_view value)
|
||||
void update_value(const std::vector<row_handle> &rows, std::string_view item_name, const item_value &value)
|
||||
{
|
||||
update_value(rows, item_name, [value](std::string_view)
|
||||
update_value(rows, item_name, [value](const item_value &)
|
||||
{ return value; });
|
||||
}
|
||||
|
||||
@@ -1101,7 +1088,7 @@ class category
|
||||
/// @brief Return the name for item with index @a ix
|
||||
/// @param ix The index number
|
||||
/// @return The name of the item
|
||||
[[nodiscard]] std::string_view get_item_name(uint16_t ix) const
|
||||
[[nodiscard]] const std::string &get_item_name(uint16_t ix) const
|
||||
{
|
||||
if (ix >= m_items.size())
|
||||
throw std::out_of_range("item index is out of range");
|
||||
|
||||
@@ -152,16 +152,16 @@ namespace detail
|
||||
virtual ~condition_impl() = default;
|
||||
|
||||
virtual condition_impl *prepare(const category &) { return this; }
|
||||
[[nodiscard]] virtual bool test(row_handle) const = 0;
|
||||
[[nodiscard]] virtual bool test(const_row_handle) const = 0;
|
||||
virtual void str(std::ostream &) const = 0;
|
||||
[[nodiscard]] virtual std::optional<row_handle> single() const { return {}; };
|
||||
[[nodiscard]] virtual std::optional<const_row_handle> single() const { return {}; };
|
||||
|
||||
virtual bool equals([[maybe_unused]] const condition_impl *rhs) const { return false; }
|
||||
};
|
||||
|
||||
struct all_condition_impl : public condition_impl
|
||||
{
|
||||
[[nodiscard]] bool test(row_handle) const override { return true; }
|
||||
[[nodiscard]] bool test(const_row_handle) const override { return true; }
|
||||
void str(std::ostream &os) const override { os << "*"; }
|
||||
};
|
||||
|
||||
@@ -244,7 +244,7 @@ class condition
|
||||
* @return true If there is a match
|
||||
* @return false If there is no match
|
||||
*/
|
||||
bool operator()(row_handle r) const
|
||||
bool operator()(const_row_handle r) const
|
||||
{
|
||||
assert(this->m_impl != nullptr);
|
||||
assert(this->m_prepared);
|
||||
@@ -265,12 +265,12 @@ class condition
|
||||
* @brief If the prepare step found out there is only one hit
|
||||
* this single hit can be returned by this method.
|
||||
*
|
||||
* @return std::optional<row_handle> The result will contain
|
||||
* @return std::optional<const_row_handle> The result will contain
|
||||
* a row reference if there is a single hit, it will be empty otherwise
|
||||
*/
|
||||
[[nodiscard]] std::optional<row_handle> single() const
|
||||
[[nodiscard]] std::optional<const_row_handle> single() const
|
||||
{
|
||||
return m_impl ? m_impl->single() : std::optional<row_handle>();
|
||||
return m_impl ? m_impl->single() : std::optional<const_row_handle>();
|
||||
}
|
||||
|
||||
friend condition operator||(condition &&a, condition &&b); /**< Return a condition which is the logical OR or condition @a and @b */
|
||||
@@ -327,7 +327,7 @@ namespace detail
|
||||
return this;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool test(row_handle r) const override
|
||||
[[nodiscard]] bool test(const_row_handle r) const override
|
||||
{
|
||||
return r[m_item_ix].empty();
|
||||
}
|
||||
@@ -354,7 +354,7 @@ namespace detail
|
||||
return this;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool test(row_handle r) const override
|
||||
[[nodiscard]] bool test(const_row_handle r) const override
|
||||
{
|
||||
return not r[m_item_ix].empty();
|
||||
}
|
||||
@@ -378,7 +378,7 @@ namespace detail
|
||||
|
||||
condition_impl *prepare(const category &c) override;
|
||||
|
||||
[[nodiscard]] bool test(row_handle r) const override
|
||||
[[nodiscard]] bool test(const_row_handle r) const override
|
||||
{
|
||||
return m_single_hit.has_value() ? *m_single_hit == r : r[m_item_ix].compare(m_value, m_icase) == 0;
|
||||
}
|
||||
@@ -388,7 +388,7 @@ namespace detail
|
||||
os << m_item_name << (m_icase ? "^ " : " ") << " == " << m_value;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<row_handle> single() const override
|
||||
[[nodiscard]] std::optional<const_row_handle> single() const override
|
||||
{
|
||||
return m_single_hit;
|
||||
}
|
||||
@@ -411,7 +411,7 @@ namespace detail
|
||||
uint16_t m_item_ix = 0;
|
||||
bool m_icase = false;
|
||||
item_value m_value;
|
||||
std::optional<row_handle> m_single_hit;
|
||||
std::optional<const_row_handle> m_single_hit;
|
||||
};
|
||||
|
||||
struct key_equals_or_empty_condition_impl : public condition_impl
|
||||
@@ -431,7 +431,7 @@ namespace detail
|
||||
return this;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool test(row_handle r) const override
|
||||
[[nodiscard]] bool test(const_row_handle r) const override
|
||||
{
|
||||
bool result = false;
|
||||
if (m_single_hit.has_value())
|
||||
@@ -446,7 +446,7 @@ namespace detail
|
||||
os << '(' << m_item_name << (m_icase ? "^ " : " ") << " == " << m_value << " OR " << m_item_name << " IS NULL)";
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<row_handle> single() const override
|
||||
[[nodiscard]] std::optional<const_row_handle> single() const override
|
||||
{
|
||||
return m_single_hit;
|
||||
}
|
||||
@@ -469,7 +469,7 @@ namespace detail
|
||||
uint16_t m_item_ix = 0;
|
||||
item_value &m_value;
|
||||
bool m_icase = false;
|
||||
std::optional<row_handle> m_single_hit;
|
||||
std::optional<const_row_handle> m_single_hit;
|
||||
};
|
||||
|
||||
struct key_compare_condition_impl : public condition_impl
|
||||
@@ -489,7 +489,7 @@ namespace detail
|
||||
return this;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool test(row_handle r) const override
|
||||
[[nodiscard]] bool test(const_row_handle r) const override
|
||||
{
|
||||
return m_compare(r, m_icase);
|
||||
}
|
||||
@@ -502,7 +502,7 @@ namespace detail
|
||||
std::string m_item_name;
|
||||
uint16_t m_item_ix = 0;
|
||||
bool m_icase = false;
|
||||
std::function<bool(row_handle, bool)> m_compare;
|
||||
std::function<bool(const_row_handle, bool)> m_compare;
|
||||
std::string m_str;
|
||||
};
|
||||
|
||||
@@ -520,7 +520,7 @@ namespace detail
|
||||
return this;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool test(row_handle r) const override
|
||||
[[nodiscard]] bool test(const_row_handle r) const override
|
||||
{
|
||||
auto txt = r[m_item_ix].get<std::string>();
|
||||
return std::regex_match(txt.begin(), txt.end(), mRx);
|
||||
@@ -546,7 +546,7 @@ namespace detail
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] bool test(row_handle r) const override
|
||||
[[nodiscard]] bool test(const_row_handle r) const override
|
||||
{
|
||||
auto &c = r.get_category();
|
||||
|
||||
@@ -578,7 +578,7 @@ namespace detail
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] bool test(row_handle r) const override
|
||||
[[nodiscard]] bool test(const_row_handle r) const override
|
||||
{
|
||||
auto &c = r.get_category();
|
||||
|
||||
@@ -648,7 +648,7 @@ namespace detail
|
||||
|
||||
condition_impl *prepare(const category &c) override;
|
||||
|
||||
[[nodiscard]] bool test(row_handle r) const override;
|
||||
[[nodiscard]] bool test(const_row_handle r) const override;
|
||||
|
||||
void str(std::ostream &os) const override
|
||||
{
|
||||
@@ -668,9 +668,9 @@ namespace detail
|
||||
os << ')';
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<row_handle> single() const override
|
||||
[[nodiscard]] std::optional<const_row_handle> single() const override
|
||||
{
|
||||
std::optional<row_handle> result;
|
||||
std::optional<const_row_handle> result;
|
||||
|
||||
for (auto sub : m_sub)
|
||||
{
|
||||
@@ -695,7 +695,7 @@ namespace detail
|
||||
static condition_impl *combine_equal(std::vector<and_condition_impl *> &subs, or_condition_impl *oc);
|
||||
|
||||
std::vector<condition_impl *> m_sub;
|
||||
std::optional<row_handle> m_single; // Potential result of index lookup
|
||||
std::optional<const_row_handle> m_single; // Potential result of index lookup
|
||||
};
|
||||
|
||||
struct or_condition_impl : public condition_impl
|
||||
@@ -731,7 +731,7 @@ namespace detail
|
||||
|
||||
condition_impl *prepare(const category &c) override;
|
||||
|
||||
[[nodiscard]] bool test(row_handle r) const override
|
||||
[[nodiscard]] bool test(const_row_handle r) const override
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
@@ -762,9 +762,9 @@ namespace detail
|
||||
os << ')';
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<row_handle> single() const override
|
||||
[[nodiscard]] std::optional<const_row_handle> single() const override
|
||||
{
|
||||
std::optional<row_handle> result;
|
||||
std::optional<const_row_handle> result;
|
||||
|
||||
for (auto sub : m_sub)
|
||||
{
|
||||
@@ -807,7 +807,7 @@ namespace detail
|
||||
return this;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool test(row_handle r) const override
|
||||
[[nodiscard]] bool test(const_row_handle r) const override
|
||||
{
|
||||
return not mA->test(r);
|
||||
}
|
||||
@@ -863,26 +863,6 @@ inline condition operator or(condition &&a, condition &&b)
|
||||
return condition(new detail::key_equals_or_empty_condition_impl(ci));
|
||||
}
|
||||
|
||||
if (typeid(*a.m_impl) == typeid(detail::key_equals_number_condition_impl) and
|
||||
typeid(*b.m_impl) == typeid(detail::key_is_empty_condition_impl))
|
||||
{
|
||||
auto ci = static_cast<detail::key_equals_number_condition_impl *>(a.m_impl);
|
||||
auto ce = static_cast<detail::key_is_empty_condition_impl *>(b.m_impl);
|
||||
|
||||
if (ci->m_item_name == ce->m_item_name)
|
||||
return condition(new detail::key_equals_number_or_empty_condition_impl(ci));
|
||||
}
|
||||
|
||||
if (typeid(*b.m_impl) == typeid(detail::key_equals_number_condition_impl) and
|
||||
typeid(*a.m_impl) == typeid(detail::key_is_empty_condition_impl))
|
||||
{
|
||||
auto ci = static_cast<detail::key_equals_number_condition_impl *>(b.m_impl);
|
||||
auto ce = static_cast<detail::key_is_empty_condition_impl *>(a.m_impl);
|
||||
|
||||
if (ci->m_item_name == ce->m_item_name)
|
||||
return condition(new detail::key_equals_number_or_empty_condition_impl(ci));
|
||||
}
|
||||
|
||||
return condition(new detail::or_condition_impl(std::move(a), std::move(b)));
|
||||
}
|
||||
|
||||
@@ -956,23 +936,15 @@ struct key
|
||||
std::string m_item_name; ///< The item name
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept Numeric = ((std::is_floating_point_v<T> or std::is_integral_v<T>) and not std::is_same_v<T, bool>);
|
||||
|
||||
/**
|
||||
* @brief Operator to create an equals condition based on a key @a key and a numeric value @a v
|
||||
*/
|
||||
template <Numeric T>
|
||||
condition operator==(const key &key, const T &v)
|
||||
{
|
||||
// TODO: change key_equals_etc... to use std::variant<double,int64_t> or something
|
||||
return condition(new detail::key_equals_number_condition_impl(key.m_item_name, static_cast<double>(v)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator to create an equals condition based on a key @a key and a value @a value
|
||||
*/
|
||||
inline condition operator==(const key &key, std::string_view value)
|
||||
|
||||
template <typename T>
|
||||
concept Numeric = ((std::is_floating_point_v<T> or std::is_integral_v<T>) and not std::is_same_v<T, bool>);
|
||||
|
||||
inline condition operator==(const key &key, const item_value &value)
|
||||
{
|
||||
if (not value.empty())
|
||||
return condition(new detail::key_equals_condition_impl({ key.m_item_name, value }));
|
||||
@@ -980,29 +952,10 @@ inline condition operator==(const key &key, std::string_view value)
|
||||
return condition(new detail::key_is_empty_condition_impl(key.m_item_name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator to create an equals condition based on a key @a key and a value @a value
|
||||
*/
|
||||
template <typename T>
|
||||
requires std::is_same_v<T, bool>
|
||||
inline condition operator==(const key &key, T value)
|
||||
{
|
||||
return condition(new detail::key_equals_condition_impl({ key.m_item_name, value ? "y" : "n" }));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator to create a not equals condition based on a key @a key and a value @a v
|
||||
*/
|
||||
template <typename T>
|
||||
condition operator!=(const key &key, const T &v)
|
||||
{
|
||||
return condition(new detail::not_condition_impl(operator==(key, v)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator to create a not equals condition based on a key @a key and a value @a value
|
||||
*/
|
||||
inline condition operator!=(const key &key, std::string_view value)
|
||||
inline condition operator!=(const key &key, const item_value &value)
|
||||
{
|
||||
return condition(new detail::not_condition_impl(operator==(key, value)));
|
||||
}
|
||||
@@ -1014,9 +967,9 @@ template <Numeric T>
|
||||
condition operator>(const key &key, const T &v)
|
||||
{
|
||||
return condition(new detail::key_compare_condition_impl(
|
||||
key.m_item_name, [item_name = key.m_item_name, v](row_handle r, bool icase)
|
||||
key.m_item_name, [item_name = key.m_item_name, v](const_row_handle r, bool icase)
|
||||
{ return r[item_name].compare(v) > 0; },
|
||||
cif::format(" > {}", v)));
|
||||
std::format(" > {}", v)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1026,7 +979,7 @@ template <Numeric T>
|
||||
condition operator>=(const key &key, const T &v)
|
||||
{
|
||||
return condition(new detail::key_compare_condition_impl(
|
||||
key.m_item_name, [item_name = key.m_item_name, v](row_handle r, bool icase)
|
||||
key.m_item_name, [item_name = key.m_item_name, v](const_row_handle r, bool icase)
|
||||
{ return r[item_name].compare(v) >= 0; },
|
||||
std::format(" >= {}", v)));
|
||||
}
|
||||
@@ -1038,7 +991,7 @@ template <Numeric T>
|
||||
condition operator<(const key &key, const T &v)
|
||||
{
|
||||
return condition(new detail::key_compare_condition_impl(
|
||||
key.m_item_name, [item_name = key.m_item_name, v](row_handle r, bool icase)
|
||||
key.m_item_name, [item_name = key.m_item_name, v](const_row_handle r, bool icase)
|
||||
{ return r[item_name].compare(v) < 0; },
|
||||
std::format(" < {}", v)));
|
||||
}
|
||||
@@ -1050,7 +1003,7 @@ template <Numeric T>
|
||||
condition operator<=(const key &key, const T &v)
|
||||
{
|
||||
return condition(new detail::key_compare_condition_impl(
|
||||
key.m_item_name, [item_name = key.m_item_name, v](row_handle r, bool icase)
|
||||
key.m_item_name, [item_name = key.m_item_name, v](const_row_handle r, bool icase)
|
||||
{ return r[item_name].compare(v) <= 0; },
|
||||
std::format(" <= {}", v)));
|
||||
}
|
||||
@@ -1061,7 +1014,7 @@ condition operator<=(const key &key, const T &v)
|
||||
inline condition operator>(const key &key, std::string_view v)
|
||||
{
|
||||
return condition(new detail::key_compare_condition_impl(
|
||||
key.m_item_name, [item_name = key.m_item_name, v](row_handle r, bool icase)
|
||||
key.m_item_name, [item_name = key.m_item_name, v](const_row_handle r, bool icase)
|
||||
{ return r[item_name].compare(v, icase) > 0; },
|
||||
std::format(" > {}", v)));
|
||||
}
|
||||
@@ -1072,7 +1025,7 @@ inline condition operator>(const key &key, std::string_view v)
|
||||
inline condition operator>=(const key &key, std::string_view v)
|
||||
{
|
||||
return condition(new detail::key_compare_condition_impl(
|
||||
key.m_item_name, [item_name = key.m_item_name, v](row_handle r, bool icase)
|
||||
key.m_item_name, [item_name = key.m_item_name, v](const_row_handle r, bool icase)
|
||||
{ return r[item_name].compare(v, icase) >= 0; },
|
||||
std::format(" >= {}", v)));
|
||||
}
|
||||
@@ -1083,7 +1036,7 @@ inline condition operator>=(const key &key, std::string_view v)
|
||||
inline condition operator<(const key &key, std::string_view v)
|
||||
{
|
||||
return condition(new detail::key_compare_condition_impl(
|
||||
key.m_item_name, [item_name = key.m_item_name, v](row_handle r, bool icase)
|
||||
key.m_item_name, [item_name = key.m_item_name, v](const_row_handle r, bool icase)
|
||||
{ return r[item_name].compare(v, icase) < 0; },
|
||||
std::format(" < {}", v)));
|
||||
}
|
||||
@@ -1094,7 +1047,7 @@ inline condition operator<(const key &key, std::string_view v)
|
||||
inline condition operator<=(const key &key, std::string_view v)
|
||||
{
|
||||
return condition(new detail::key_compare_condition_impl(
|
||||
key.m_item_name, [item_name = key.m_item_name, v](row_handle r, bool icase)
|
||||
key.m_item_name, [item_name = key.m_item_name, v](const_row_handle r, bool icase)
|
||||
{ return r[item_name].compare(v, icase) <= 0; },
|
||||
std::format(" <= {}", v)));
|
||||
}
|
||||
|
||||
@@ -42,9 +42,6 @@ class file;
|
||||
class parser;
|
||||
|
||||
class row;
|
||||
class row_handle;
|
||||
|
||||
class item;
|
||||
struct item_handle;
|
||||
|
||||
} // namespace cif
|
||||
|
||||
@@ -31,10 +31,13 @@
|
||||
#include "cif++/utilities.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <catch2/catch_tostring.hpp>
|
||||
#include <cctype>
|
||||
#include <charconv>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
@@ -56,7 +59,8 @@
|
||||
namespace cif
|
||||
{
|
||||
|
||||
class row_handle;
|
||||
class category;
|
||||
class row;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/** @brief item is a transient class that is used to pass data into rows
|
||||
@@ -97,8 +101,9 @@ enum class item_value_type
|
||||
INT,
|
||||
FLOAT,
|
||||
TEXT,
|
||||
MISSING,
|
||||
EMPTY // This is the real NULL in SQL terms
|
||||
|
||||
INAPPLICABLE,
|
||||
MISSING
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@@ -113,12 +118,21 @@ concept FloatType = std::is_floating_point_v<std::remove_cvref_t<T>>;
|
||||
template <typename T>
|
||||
concept StringType = (std::is_assignable_v<std::string, T> and not std::is_integral_v<T> and not std::is_floating_point_v<T>);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/// \cond
|
||||
template <typename T>
|
||||
inline constexpr bool is_optional_v = false;
|
||||
template <typename T>
|
||||
inline constexpr bool is_optional_v<std::optional<T>> = true;
|
||||
/// \endcond
|
||||
|
||||
class item_value
|
||||
{
|
||||
public:
|
||||
item_value() noexcept
|
||||
{
|
||||
m_data.m_type = item_value_type::EMPTY;
|
||||
m_data.m_type = item_value_type::MISSING;
|
||||
}
|
||||
|
||||
item_value(item_value_type type) noexcept
|
||||
@@ -134,14 +148,17 @@ class item_value
|
||||
case item_value_type::BOOLEAN: m_data.m_value = rhs.m_data.m_value.m_boolean; break;
|
||||
case item_value_type::INT: m_data.m_value = rhs.m_data.m_value.m_integer; break;
|
||||
case item_value_type::FLOAT: m_data.m_value = rhs.m_data.m_value.m_float; break;
|
||||
case item_value_type::TEXT: m_data.m_value = rhs.m_data.sv(); break;
|
||||
case item_value_type::TEXT:
|
||||
m_data.m_len = rhs.m_data.m_len;
|
||||
m_data.m_value = rhs.m_data.sv();
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
item_value(std::nullptr_t)
|
||||
{
|
||||
m_data.m_type = item_value_type::EMPTY;
|
||||
m_data.m_type = item_value_type::MISSING;
|
||||
}
|
||||
|
||||
template <BooleanType T>
|
||||
@@ -191,8 +208,14 @@ class item_value
|
||||
|
||||
template <typename T>
|
||||
item_value(std::optional<T> v)
|
||||
: item_value(v.has_value() ? *v : nullptr)
|
||||
{
|
||||
if (v.has_value())
|
||||
{
|
||||
item_value iv{ *v };
|
||||
swap(*this, iv);
|
||||
}
|
||||
else
|
||||
m_data.m_type = item_value_type::MISSING;
|
||||
}
|
||||
|
||||
item_value(item_value &&rhs) noexcept
|
||||
@@ -208,15 +231,19 @@ class item_value
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
constexpr bool is_null() const noexcept { return m_data.m_type == item_value_type::MISSING; }
|
||||
constexpr bool is_empty() const noexcept { return m_data.m_type == item_value_type::EMPTY; }
|
||||
constexpr bool is_string() const noexcept { return m_data.m_type == item_value_type::TEXT; }
|
||||
constexpr bool is_number() const noexcept { return is_number_int() or is_number_float(); }
|
||||
constexpr bool is_number_int() const noexcept { return m_data.m_type == item_value_type::INT; }
|
||||
constexpr bool is_number_float() const noexcept { return m_data.m_type == item_value_type::FLOAT; }
|
||||
constexpr bool is_boolean() const noexcept { return m_data.m_type == item_value_type::BOOLEAN; }
|
||||
[[nodiscard]] constexpr bool is_inapplicable() const noexcept { return m_data.m_type == item_value_type::INAPPLICABLE; }
|
||||
[[nodiscard]] constexpr bool is_missing() const noexcept { return m_data.m_type == item_value_type::MISSING; }
|
||||
[[nodiscard]] constexpr bool is_null() const noexcept { return is_inapplicable() or is_missing(); }
|
||||
|
||||
constexpr item_value_type type() const { return m_data.m_type; }
|
||||
[[nodiscard]] constexpr bool is_string() const noexcept { return m_data.m_type == item_value_type::TEXT; }
|
||||
|
||||
[[nodiscard]] constexpr bool is_number_int() const noexcept { return m_data.m_type == item_value_type::INT; }
|
||||
[[nodiscard]] constexpr bool is_number_float() const noexcept { return m_data.m_type == item_value_type::FLOAT; }
|
||||
[[nodiscard]] constexpr bool is_number() const noexcept { return is_number_int() or is_number_float(); }
|
||||
|
||||
[[nodiscard]] constexpr bool is_boolean() const noexcept { return m_data.m_type == item_value_type::BOOLEAN; }
|
||||
|
||||
[[nodiscard]] constexpr item_value_type type() const { return m_data.m_type; }
|
||||
|
||||
explicit operator bool() const noexcept
|
||||
{
|
||||
@@ -227,18 +254,18 @@ class item_value
|
||||
case item_value_type::INT: result = m_data.m_value.m_integer != 0; break;
|
||||
case item_value_type::FLOAT: result = m_data.m_value.m_float != 0; break;
|
||||
case item_value_type::TEXT: result = m_data.m_len != 0; break;
|
||||
case item_value_type::MISSING:
|
||||
case item_value_type::EMPTY: result = false; break;
|
||||
case item_value_type::INAPPLICABLE:
|
||||
case item_value_type::MISSING: result = false; break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool empty() const noexcept
|
||||
[[nodiscard]] bool empty() const noexcept
|
||||
{
|
||||
switch (m_data.m_type)
|
||||
{
|
||||
case item_value_type::INAPPLICABLE:
|
||||
case item_value_type::MISSING:
|
||||
case item_value_type::EMPTY:
|
||||
return true;
|
||||
|
||||
case item_value_type::TEXT:
|
||||
@@ -252,12 +279,12 @@ class item_value
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
template <StringType T>
|
||||
inline std::string get() const
|
||||
[[nodiscard]] inline std::string get() const
|
||||
{
|
||||
switch (m_data.m_type)
|
||||
{
|
||||
case item_value_type::EMPTY:
|
||||
case item_value_type::MISSING:
|
||||
case item_value_type::INAPPLICABLE:
|
||||
return "";
|
||||
|
||||
case item_value_type::TEXT:
|
||||
@@ -284,7 +311,7 @@ class item_value
|
||||
}
|
||||
|
||||
template <IntegralType T>
|
||||
std::remove_cvref_t<T> get() const
|
||||
[[nodiscard]] std::remove_cvref_t<T> get() const
|
||||
{
|
||||
switch (m_data.m_type)
|
||||
{
|
||||
@@ -301,6 +328,9 @@ class item_value
|
||||
auto &&[ptr, ec] = std::from_chars(sv.data(), sv.data() + sv.length(), v);
|
||||
if (ec != std::errc{})
|
||||
throw std::system_error(std::make_error_code(ec));
|
||||
if (ptr != sv.data() + sv.length())
|
||||
throw std::invalid_argument("String value does not contain only an integer");
|
||||
|
||||
return v;
|
||||
}
|
||||
default:
|
||||
@@ -309,7 +339,7 @@ class item_value
|
||||
}
|
||||
|
||||
template <FloatType T>
|
||||
std::remove_cvref_t<T> get() const
|
||||
[[nodiscard]] std::remove_cvref_t<T> get() const
|
||||
{
|
||||
switch (m_data.m_type)
|
||||
{
|
||||
@@ -326,6 +356,8 @@ class item_value
|
||||
auto &&[ptr, ec] = std::from_chars(sv.data(), sv.data() + sv.length(), v);
|
||||
if (ec != std::errc{})
|
||||
throw std::system_error(std::make_error_code(ec));
|
||||
if (ptr != sv.data() + sv.length())
|
||||
throw std::invalid_argument("String value does not contain only a floating point number");
|
||||
return v;
|
||||
}
|
||||
default:
|
||||
@@ -334,7 +366,7 @@ class item_value
|
||||
}
|
||||
|
||||
template <BooleanType T>
|
||||
std::remove_cvref_t<T> get() const
|
||||
[[nodiscard]] std::remove_cvref_t<T> get() const
|
||||
{
|
||||
switch (m_data.m_type)
|
||||
{
|
||||
@@ -352,19 +384,28 @@ class item_value
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::optional<T> get() const
|
||||
requires is_optional_v<T>
|
||||
[[nodiscard]] auto get() const
|
||||
{
|
||||
switch (m_data.m_type)
|
||||
{
|
||||
case item_value_type::INAPPLICABLE:
|
||||
case item_value_type::MISSING:
|
||||
case item_value_type::EMPTY:
|
||||
return {};
|
||||
return T{};
|
||||
|
||||
default:
|
||||
return get<T>();
|
||||
{
|
||||
auto v = get<typename T::value_type>();
|
||||
return T{ v };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string str() const
|
||||
{
|
||||
return get<std::string>();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
friend void swap(item_value &a, item_value &b) noexcept
|
||||
@@ -403,31 +444,28 @@ class item_value
|
||||
case item_value_type::INT: return m_data.m_value.m_integer == rhs.m_data.m_value.m_integer;
|
||||
case item_value_type::FLOAT: return m_data.m_value.m_float == rhs.m_data.m_value.m_float;
|
||||
case item_value_type::TEXT: return m_data.sv() == rhs.m_data.sv();
|
||||
case item_value_type::MISSING:
|
||||
case item_value_type::EMPTY: return true;
|
||||
case item_value_type::INAPPLICABLE:
|
||||
case item_value_type::MISSING: return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int compare(const item_value &b, bool ignore_case = false) const noexcept;
|
||||
[[nodiscard]] int compare(const item_value &b, bool ignore_case = false) const noexcept;
|
||||
|
||||
friend std::ostream operator<<(std::ostream &os, const item_value &v);
|
||||
friend std::ostream &operator<<(std::ostream &os, const item_value &v);
|
||||
|
||||
private:
|
||||
union value
|
||||
{
|
||||
bool m_boolean;
|
||||
int64_t m_integer;
|
||||
int64_t m_integer{};
|
||||
double m_float;
|
||||
char m_local_str[8];
|
||||
char *m_str;
|
||||
|
||||
value()
|
||||
: m_integer(0)
|
||||
{
|
||||
}
|
||||
value() = default;
|
||||
|
||||
value(bool v)
|
||||
: m_boolean(v)
|
||||
@@ -453,7 +491,7 @@ class item_value
|
||||
m_str[s.length()] = 0;
|
||||
}
|
||||
else
|
||||
memcpy(m_local_str, s.data(), s.length() + 1);
|
||||
std::memcpy(m_local_str, s.data(), s.length() + 1);
|
||||
}
|
||||
|
||||
value(item_value_type t)
|
||||
@@ -470,7 +508,7 @@ class item_value
|
||||
|
||||
struct data
|
||||
{
|
||||
item_value_type m_type = item_value_type::EMPTY;
|
||||
item_value_type m_type = item_value_type::MISSING;
|
||||
uint32_t m_len{};
|
||||
value m_value{};
|
||||
|
||||
@@ -481,7 +519,13 @@ class item_value
|
||||
}
|
||||
|
||||
data() noexcept = default;
|
||||
data(data &&) noexcept = default;
|
||||
data(data &&rhs) noexcept
|
||||
{
|
||||
std::swap(m_type, rhs.m_type);
|
||||
std::swap(m_len, rhs.m_len);
|
||||
std::swap(m_value, rhs.m_value);
|
||||
}
|
||||
|
||||
data(const data &) noexcept = delete;
|
||||
data &operator=(data &&) noexcept = delete;
|
||||
data &operator=(const data &) noexcept = delete;
|
||||
@@ -515,7 +559,7 @@ class item
|
||||
/// content the character '.', i.e. an inapplicable value.
|
||||
item(std::string name)
|
||||
: m_name(std::move(name))
|
||||
, m_value(item_value_type::EMPTY)
|
||||
, m_value(item_value_type::MISSING)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -525,98 +569,31 @@ class item
|
||||
{
|
||||
}
|
||||
|
||||
// /// \brief constructor for an item with name \a name and as
|
||||
// /// content the character '.', i.e. an inapplicable value.
|
||||
// item(std::string_view name, std::nullptr_t)
|
||||
// : m_name(name)
|
||||
// , m_value(item_value_type::EMPTY)
|
||||
// {
|
||||
// }
|
||||
|
||||
// /// \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)
|
||||
// : m_name(name)
|
||||
// , m_value(std::string_view{ &value, 1 })
|
||||
// {
|
||||
// }
|
||||
|
||||
// /// \brief constructor for an item with name \a name and as
|
||||
// /// content the formatted floating point value \a value
|
||||
// template <FloatType T>
|
||||
// item(std::string_view name, T value)
|
||||
// : m_name(name)
|
||||
// , m_value(value)
|
||||
// {
|
||||
// }
|
||||
|
||||
// /// \brief constructor for an item with name \a name and as
|
||||
// /// content the formatted floating point value \a value with
|
||||
// /// precision \a precision
|
||||
// template <FloatType T>
|
||||
// item(std::string_view name, T value, int precision)
|
||||
// : m_name(name)
|
||||
// , m_value(value, precision)
|
||||
// {
|
||||
// }
|
||||
|
||||
// /// \brief constructor for an item with name \a name and as
|
||||
// /// content the formatted integral value \a value
|
||||
// template <IntegralType T>
|
||||
// item(const std::string_view name, T value)
|
||||
// : m_name(name)
|
||||
// , m_value(value)
|
||||
// {
|
||||
// }
|
||||
|
||||
// // TODO: Perhaps introduce a real boolean type?
|
||||
// /// \brief constructor for an item with name \a name and as
|
||||
// /// content the formatted boolean value \a value
|
||||
// template <BooleanType T>
|
||||
// item(const std::string_view name, T value)
|
||||
// : m_name(name)
|
||||
// , m_value(value)
|
||||
// {
|
||||
// }
|
||||
|
||||
// /// \brief constructor for an item with name \a name and as
|
||||
// /// content value \a value
|
||||
// item(const std::string_view name, std::string_view value)
|
||||
// : m_name(name)
|
||||
// , m_value(value)
|
||||
// {
|
||||
// }
|
||||
|
||||
// /// \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)
|
||||
// , m_value(item_value_type::MISSING)
|
||||
// {
|
||||
// if (value.has_value())
|
||||
// m_value = *value;
|
||||
// }
|
||||
|
||||
// /// \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)
|
||||
// , m_value(item_value_type::MISSING)
|
||||
// {
|
||||
// if (value.has_value())
|
||||
// m_value = item_value(*value, precision);
|
||||
// }
|
||||
|
||||
/** @cond */
|
||||
item(const item &rhs) = default;
|
||||
item(item &&rhs) noexcept = default;
|
||||
item &operator=(const item &rhs) = default;
|
||||
item &operator=(item &&rhs) noexcept = default;
|
||||
item(const item &rhs)
|
||||
: m_name(rhs.m_name)
|
||||
, m_value(rhs.m_value)
|
||||
{
|
||||
}
|
||||
|
||||
item(item &&rhs)
|
||||
{
|
||||
swap(*this, rhs);
|
||||
}
|
||||
|
||||
item &operator=(item rhs) noexcept
|
||||
{
|
||||
swap(*this, rhs);
|
||||
return *this;
|
||||
}
|
||||
/** @endcond */
|
||||
|
||||
friend void swap(item &a, item &b) noexcept
|
||||
{
|
||||
std::swap(a.m_name, b.m_name);
|
||||
std::swap(a.m_value, b.m_value);
|
||||
}
|
||||
|
||||
const std::string &name() const { return m_name; } ///< Return the name of the item
|
||||
const item_value &value() const & { return m_value; } ///< Return the value of the item
|
||||
item_value &value() & { return m_value; } ///< Return the value of the item
|
||||
@@ -627,11 +604,11 @@ class item
|
||||
/// \brief empty means either null or unknown
|
||||
bool empty() const { return m_value.empty(); }
|
||||
|
||||
/// \brief returns true if the item contains '.'
|
||||
/// \brief returns true if the item contains '.' or '?'
|
||||
bool is_null() const { return m_value.is_null(); }
|
||||
|
||||
/// \brief returns true if the item contains '?'
|
||||
bool is_unknown() const { return m_value.is_empty(); }
|
||||
bool is_unknown() const { return m_value.is_missing(); }
|
||||
|
||||
// /// \brief the length of the value string
|
||||
// std::size_t length() const { return m_value.length(); }
|
||||
@@ -646,7 +623,7 @@ class item
|
||||
return value();
|
||||
}
|
||||
|
||||
auto operator<=>(const item &rhs) const = default;
|
||||
// auto operator<=>(const item &rhs) const = default;
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
@@ -654,18 +631,13 @@ class item
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Transient object to access stored data
|
||||
|
||||
/// \brief This is item_handle, it is used to access the data stored in item_value.
|
||||
/// \brief This is item_handle, it is used to access the data stored in
|
||||
/// item_value's in rows
|
||||
|
||||
struct item_handle
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
// conversion helper class
|
||||
template <typename T, typename = void>
|
||||
struct item_value_as;
|
||||
/** @endcond */
|
||||
item_handle() = delete;
|
||||
|
||||
/**
|
||||
* @brief Assign value @a value to the item referenced
|
||||
@@ -674,73 +646,44 @@ struct item_handle
|
||||
* @param value The value
|
||||
* @return reference to this item_handle
|
||||
*/
|
||||
item_handle &operator=(item_value value);
|
||||
|
||||
[[nodiscard]] item_value_type &value();
|
||||
[[nodiscard]] const item_value &value() const;
|
||||
|
||||
[[nodiscard]] constexpr bool is_inapplicable() const noexcept { return value().type() == item_value_type::INAPPLICABLE; }
|
||||
[[nodiscard]] constexpr bool is_missing() const noexcept { return value().type() == item_value_type::MISSING; }
|
||||
[[nodiscard]] constexpr bool is_null() const noexcept { return is_inapplicable() or is_missing(); }
|
||||
|
||||
[[nodiscard]] constexpr bool is_string() const noexcept { return value().type() == item_value_type::TEXT; }
|
||||
|
||||
[[nodiscard]] constexpr bool is_number_int() const noexcept { return value().type() == item_value_type::INT; }
|
||||
[[nodiscard]] constexpr bool is_number_float() const noexcept { return value().type() == item_value_type::FLOAT; }
|
||||
[[nodiscard]] constexpr bool is_number() const noexcept { return is_number_int() or is_number_float(); }
|
||||
|
||||
[[nodiscard]] constexpr bool is_boolean() const noexcept { return value().type() == item_value_type::BOOLEAN; }
|
||||
|
||||
[[nodiscard]] auto type() const { return value().type(); }
|
||||
|
||||
template <typename T>
|
||||
item_handle &operator=(const T &value)
|
||||
auto get() const
|
||||
{
|
||||
assign_value(item{ "", value }.value());
|
||||
return *this;
|
||||
return value().template get<T>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
template <typename T>
|
||||
item_handle &operator=(T &&value)
|
||||
auto as() const
|
||||
{
|
||||
assign_value(item{ "", std::forward<T>(value) }.value());
|
||||
return *this;
|
||||
return value().template get<T>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
template <std::size_t N>
|
||||
item_handle &operator=(const char (&value)[N])
|
||||
[[nodiscard]] auto str() const
|
||||
{
|
||||
assign_value(item{ "", std::move(value) }.value());
|
||||
return *this;
|
||||
return value().str();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A method with a variable number of arguments that will be concatenated and
|
||||
* assigned as a string. Use it like this:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* cif::item_handle ih;
|
||||
* is.os("The result of ", 1, " * ", 42, " is of course ", 42);
|
||||
* @endcode
|
||||
*
|
||||
* And the content will then be `The result of 1 * 42 is of course 42`.
|
||||
*
|
||||
* @tparam Ts Types of the parameters
|
||||
* @param v The parameters to concatenate
|
||||
*/
|
||||
template <typename... Ts>
|
||||
void os(const Ts &...v)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
((ss << v), ...);
|
||||
this->operator=(ss.str());
|
||||
}
|
||||
|
||||
/** Swap contents of this and @a b */
|
||||
void swap(item_handle &b);
|
||||
|
||||
/** Return the contents of this item as type @tparam T */
|
||||
template <typename T = std::string>
|
||||
[[nodiscard]] auto as() const -> T
|
||||
{
|
||||
using value_type = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
return item_value_as<value_type>::convert(*this);
|
||||
}
|
||||
/** Swap contents of @a a and @a b */
|
||||
friend void swap(item_handle &a, item_handle &b) noexcept;
|
||||
|
||||
/** Return the contents of this item as type @tparam T or, if not
|
||||
* set, use @a dv as the default value.
|
||||
@@ -748,7 +691,7 @@ struct item_handle
|
||||
template <typename T>
|
||||
[[nodiscard]] auto value_or(const T &dv) const
|
||||
{
|
||||
return empty() ? dv : this->as<T>();
|
||||
return empty() ? dv : this->get<T>();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -762,21 +705,25 @@ struct item_handle
|
||||
* @param icase Flag indicating if we should compare character case sensitive
|
||||
* @return -1, 0 or 1
|
||||
*/
|
||||
template <typename T>
|
||||
[[nodiscard]] int compare(const T &value, bool icase = true) const noexcept
|
||||
|
||||
[[nodiscard]] int compare(const item_value &value, bool icase = true) const noexcept
|
||||
{
|
||||
return item_value_as<T>::compare(*this, value, icase);
|
||||
return this->value().compare(value, icase);
|
||||
}
|
||||
|
||||
[[nodiscard]] int compare(const item_handle &value, bool icase = true) const noexcept
|
||||
{
|
||||
return compare(value.value(), icase);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare the value contained with the value @a value and
|
||||
* return true if both are equal.
|
||||
*/
|
||||
template <typename T>
|
||||
[[nodiscard]] bool operator==(const T &value) const noexcept
|
||||
[[nodiscard]] bool operator==(const item_value &value) const noexcept
|
||||
{
|
||||
// TODO: icase or not icase?
|
||||
return item_value_as<T>::compare(*this, value, true) == 0;
|
||||
return this->value().compare(value) != 0;
|
||||
}
|
||||
|
||||
// We may not have C++20 yet...
|
||||
@@ -798,29 +745,14 @@ struct item_handle
|
||||
*/
|
||||
[[nodiscard]] bool empty() const
|
||||
{
|
||||
auto txt = text();
|
||||
return txt.empty() or (txt.length() == 1 and (txt.front() == '.' or txt.front() == '?'));
|
||||
return this->value().empty();
|
||||
}
|
||||
|
||||
/** Easy way to test for an empty item */
|
||||
explicit operator bool() const { return not empty(); }
|
||||
|
||||
/// is_null return true if the item contains '.'
|
||||
[[nodiscard]] bool is_null() const
|
||||
{
|
||||
auto txt = text();
|
||||
return txt.length() == 1 and txt.front() == '.';
|
||||
}
|
||||
|
||||
/// is_unknown returns true if the item contains '?'
|
||||
[[nodiscard]] bool is_unknown() const
|
||||
{
|
||||
auto txt = text();
|
||||
return txt.length() == 1 and txt.front() == '?';
|
||||
}
|
||||
|
||||
/** Return a std::string_view for the contents */
|
||||
[[nodiscard]] std::string_view text() const;
|
||||
[[nodiscard]] std::string_view text_() const;
|
||||
|
||||
/**
|
||||
* @brief Construct a new item handle object
|
||||
@@ -828,227 +760,148 @@ struct item_handle
|
||||
* @param item Item index
|
||||
* @param row Reference to the row
|
||||
*/
|
||||
item_handle(uint16_t item, row_handle &row)
|
||||
: m_item_ix(item)
|
||||
, m_row_handle(row)
|
||||
item_handle(category &cat, row &row, uint16_t item_ix)
|
||||
: m_category(cat)
|
||||
, m_row(row)
|
||||
, m_item_ix(item_ix)
|
||||
{
|
||||
}
|
||||
|
||||
/** A variable holding an empty item */
|
||||
CIFPP_EXPORT static const item_handle s_null_item;
|
||||
|
||||
/** friend to swap two item handles */
|
||||
friend void swap(item_handle a, item_handle b)
|
||||
{
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
private:
|
||||
item_handle() noexcept;
|
||||
|
||||
category &m_category;
|
||||
row &m_row;
|
||||
uint16_t m_item_ix;
|
||||
row_handle &m_row_handle;
|
||||
|
||||
void assign_value(std::string_view value);
|
||||
void assign_value(item_value value);
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Transient object to access stored data
|
||||
|
||||
/// \brief This is item_handle, it is used to access the data stored in item_value.
|
||||
|
||||
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 const_item_handle
|
||||
{
|
||||
using value_type = std::remove_reference_t<std::remove_cv_t<T>>;
|
||||
public:
|
||||
const_item_handle() = delete;
|
||||
|
||||
static value_type convert(const item_handle &ref)
|
||||
[[nodiscard]] const item_value &value() const;
|
||||
|
||||
[[nodiscard]] constexpr bool is_inapplicable() const noexcept { return value().type() == item_value_type::INAPPLICABLE; }
|
||||
[[nodiscard]] constexpr bool is_missing() const noexcept { return value().type() == item_value_type::MISSING; }
|
||||
[[nodiscard]] constexpr bool is_null() const noexcept { return is_inapplicable() or is_missing(); }
|
||||
|
||||
[[nodiscard]] constexpr bool is_string() const noexcept { return value().type() == item_value_type::TEXT; }
|
||||
|
||||
[[nodiscard]] constexpr bool is_number_int() const noexcept { return value().type() == item_value_type::INT; }
|
||||
[[nodiscard]] constexpr bool is_number_float() const noexcept { return value().type() == item_value_type::FLOAT; }
|
||||
[[nodiscard]] constexpr bool is_number() const noexcept { return is_number_int() or is_number_float(); }
|
||||
|
||||
[[nodiscard]] constexpr bool is_boolean() const noexcept { return value().type() == item_value_type::BOOLEAN; }
|
||||
|
||||
[[nodiscard]] auto type() const { return value().type(); }
|
||||
|
||||
template <typename T>
|
||||
auto get() const
|
||||
{
|
||||
value_type result = {};
|
||||
|
||||
if (not ref.empty())
|
||||
{
|
||||
auto txt = ref.text();
|
||||
|
||||
auto b = txt.data();
|
||||
auto e = txt.data() + txt.size();
|
||||
|
||||
std::from_chars_result r = (b + 1 < e and *b == '+' and std::isdigit(b[1])) //
|
||||
? from_chars(b + 1, e, result)
|
||||
: from_chars(b, e, result);
|
||||
|
||||
if (r.ec != std::errc{} or r.ptr != e)
|
||||
{
|
||||
result = {};
|
||||
if (cif::VERBOSE)
|
||||
{
|
||||
if (r.ec == std::errc::invalid_argument)
|
||||
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';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return value().template get<T>();
|
||||
}
|
||||
|
||||
static int compare(const item_handle &ref, const T &value, bool icase) noexcept
|
||||
template <typename T>
|
||||
auto as() const
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
auto txt = ref.text();
|
||||
|
||||
if (ref.empty())
|
||||
result = 1;
|
||||
else
|
||||
{
|
||||
value_type v = {};
|
||||
|
||||
auto b = txt.data();
|
||||
auto e = txt.data() + txt.size();
|
||||
|
||||
std::from_chars_result r = (b + 1 < e and *b == '+' and std::isdigit(b[1]))
|
||||
? from_chars(b + 1, e, v)
|
||||
: from_chars(b, e, v);
|
||||
|
||||
if (r.ec != std::errc{} or r.ptr != e)
|
||||
{
|
||||
if (cif::VERBOSE)
|
||||
{
|
||||
if (r.ec == std::errc::invalid_argument)
|
||||
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;
|
||||
}
|
||||
else if (std::abs(v - value) <= std::numeric_limits<value_type>::epsilon())
|
||||
result = 0;
|
||||
else if (v < value)
|
||||
result = -1;
|
||||
else if (v > value)
|
||||
result = 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
return value().template get<T>();
|
||||
}
|
||||
|
||||
[[nodiscard]] auto str() const
|
||||
{
|
||||
return value().str();
|
||||
}
|
||||
|
||||
/** Return the contents of this item as type @tparam T or, if not
|
||||
* set, use @a dv as the default value.
|
||||
*/
|
||||
template <typename T>
|
||||
[[nodiscard]] auto value_or(const T &dv) const
|
||||
{
|
||||
return empty() ? dv : this->get<T>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare the contents of this item with value @a value
|
||||
* optionally ignoring character case, if @a icase is true.
|
||||
* Returns 0 if both are equal, -1 if this sorts before @a value
|
||||
* and 1 if this sorts after @a value
|
||||
*
|
||||
* @tparam T Type of the value @a value
|
||||
* @param value The value to compare with
|
||||
* @param icase Flag indicating if we should compare character case sensitive
|
||||
* @return -1, 0 or 1
|
||||
*/
|
||||
|
||||
[[nodiscard]] int compare(const item_value &value, bool icase = true) const noexcept
|
||||
{
|
||||
return this->value().compare(value, icase);
|
||||
}
|
||||
|
||||
[[nodiscard]] int compare(const const_item_handle &value, bool icase = true) const noexcept
|
||||
{
|
||||
return compare(value.value(), icase);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare the value contained with the value @a value and
|
||||
* return true if both are equal.
|
||||
*/
|
||||
[[nodiscard]] bool operator==(const item_value &value) const noexcept
|
||||
{
|
||||
// TODO: icase or not icase?
|
||||
return this->value().compare(value) != 0;
|
||||
}
|
||||
|
||||
// We may not have C++20 yet...
|
||||
|
||||
/**
|
||||
* @brief Compare the value contained with the value @a value and
|
||||
* return true if both are not equal.
|
||||
*/
|
||||
template <typename T>
|
||||
[[nodiscard]] bool operator!=(const T &value) const noexcept
|
||||
{
|
||||
return not operator==(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if the content string is empty or
|
||||
* only contains '.' meaning null or '?' meaning unknown
|
||||
* in a mmCIF context
|
||||
*/
|
||||
[[nodiscard]] bool empty() const
|
||||
{
|
||||
return this->value().empty();
|
||||
}
|
||||
|
||||
/** Easy way to test for an empty item */
|
||||
explicit operator bool() const { return not empty(); }
|
||||
|
||||
/** Return a std::string_view for the contents */
|
||||
[[nodiscard]] std::string_view text_() const;
|
||||
|
||||
/**
|
||||
* @brief Construct a new item handle object
|
||||
*
|
||||
* @param item Item index
|
||||
* @param row Reference to the row
|
||||
*/
|
||||
const_item_handle(const category &cat, const row &row, uint16_t item_ix)
|
||||
: m_category(cat)
|
||||
, m_row(row)
|
||||
, m_item_ix(item_ix)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
const category &m_category;
|
||||
const row &m_row;
|
||||
uint16_t m_item_ix;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct item_handle::item_value_as<std::optional<T>>
|
||||
{
|
||||
static std::optional<T> convert(const item_handle &ref)
|
||||
{
|
||||
std::optional<T> result;
|
||||
if (ref)
|
||||
result = ref.as<T>();
|
||||
return result;
|
||||
}
|
||||
|
||||
static int compare(const item_handle &ref, std::optional<T> value, bool icase) noexcept
|
||||
{
|
||||
if (ref.empty() and not value)
|
||||
return 0;
|
||||
|
||||
if (ref.empty())
|
||||
return -1;
|
||||
else if (not value)
|
||||
return 1;
|
||||
else
|
||||
return ref.compare(*value, icase);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct item_handle::item_value_as<T, std::enable_if_t<std::is_same_v<T, bool>>>
|
||||
{
|
||||
static bool convert(const item_handle &ref)
|
||||
{
|
||||
bool result = false;
|
||||
if (not ref.empty())
|
||||
result = iequals(ref.text(), "y");
|
||||
return result;
|
||||
}
|
||||
|
||||
static int compare(const item_handle &ref, bool value, bool icase) noexcept
|
||||
{
|
||||
bool rv = convert(ref);
|
||||
return value && rv ? 0
|
||||
: (rv < value ? -1 : 1);
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
struct item_handle::item_value_as<char[N]>
|
||||
{
|
||||
static std::string convert(const item_handle &ref)
|
||||
{
|
||||
if (ref.empty())
|
||||
return {};
|
||||
return { ref.text().data(), ref.text().size() };
|
||||
}
|
||||
|
||||
static int compare(const item_handle &ref, const char (&value)[N], bool icase) noexcept
|
||||
{
|
||||
return icase ? cif::icompare(ref.text(), value) : ref.text().compare(value);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct item_handle::item_value_as<T, std::enable_if_t<std::is_same_v<T, const char *>>>
|
||||
{
|
||||
static std::string convert(const item_handle &ref)
|
||||
{
|
||||
if (ref.empty())
|
||||
return {};
|
||||
return { ref.text().data(), ref.text().size() };
|
||||
}
|
||||
|
||||
static int compare(const item_handle &ref, const char *value, bool icase) noexcept
|
||||
{
|
||||
return icase ? cif::icompare(ref.text(), value) : ref.text().compare(value);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct item_handle::item_value_as<T, std::enable_if_t<std::is_same_v<T, std::string_view>>>
|
||||
{
|
||||
static std::string convert(const item_handle &ref)
|
||||
{
|
||||
if (ref.empty())
|
||||
return {};
|
||||
return { ref.text().data(), ref.text().size() };
|
||||
}
|
||||
|
||||
static int compare(const item_handle &ref, const std::string_view &value, bool icase) noexcept
|
||||
{
|
||||
return icase ? cif::icompare(ref.text(), value) : ref.text().compare(value);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct item_handle::item_value_as<T, std::enable_if_t<std::is_same_v<T, std::string>>>
|
||||
{
|
||||
static std::string convert(const item_handle &ref)
|
||||
{
|
||||
if (ref.empty())
|
||||
return {};
|
||||
return { ref.text().data(), ref.text().size() };
|
||||
}
|
||||
|
||||
static int compare(const item_handle &ref, const std::string &value, bool icase) noexcept
|
||||
{
|
||||
return icase ? cif::icompare(ref.text(), value) : ref.text().compare(value);
|
||||
}
|
||||
};
|
||||
|
||||
/** @endcond */
|
||||
|
||||
} // namespace cif
|
||||
|
||||
namespace std
|
||||
@@ -1075,4 +928,3 @@ struct tuple_element<1, ::cif::item>
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ class iterator_impl_base
|
||||
|
||||
template <bool C, typename... T2s>
|
||||
iterator_impl_base(const iterator_impl_base<C, T2s...> &rhs)
|
||||
: m_current(const_cast<row_handle&>(rhs.m_current))
|
||||
: m_current(rhs.m_current)
|
||||
, m_value(rhs.m_value)
|
||||
, m_item_ix(rhs.m_item_ix)
|
||||
{
|
||||
@@ -99,7 +99,7 @@ class iterator_impl_base
|
||||
|
||||
template <bool C>
|
||||
iterator_impl_base(iterator_impl_base<C, Ts...> &rhs)
|
||||
: m_current(const_cast<row_handle&>(rhs.m_current))
|
||||
: m_current(rhs.m_current)
|
||||
, m_value(rhs.m_value)
|
||||
, m_item_ix(rhs.m_item_ix)
|
||||
{
|
||||
@@ -108,7 +108,7 @@ class iterator_impl_base
|
||||
|
||||
template <bool C>
|
||||
iterator_impl_base(const iterator_impl_base<C> &rhs, const std::array<uint16_t, N> &cix)
|
||||
: m_current(const_cast<row_handle&>(rhs.m_current))
|
||||
: m_current(rhs.m_current)
|
||||
, m_item_ix(cix)
|
||||
{
|
||||
m_value = get(std::make_index_sequence<N>());
|
||||
@@ -144,7 +144,7 @@ class iterator_impl_base
|
||||
return &m_value;
|
||||
}
|
||||
|
||||
operator const row_handle() const
|
||||
operator const_row_handle() const
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
@@ -195,7 +195,7 @@ class iterator_impl_base
|
||||
return m_current ? tuple_type{ m_current[m_item_ix[Is]].template as<Ts>()... } : tuple_type{};
|
||||
}
|
||||
|
||||
row_handle m_current;
|
||||
std::conditional_t<Const, const_row_handle, row_handle> m_current;
|
||||
tuple_type m_value;
|
||||
std::array<uint16_t, N> m_item_ix;
|
||||
};
|
||||
@@ -218,10 +218,11 @@ class iterator_impl_base<Const>
|
||||
friend class category;
|
||||
|
||||
using category_type = std::conditional_t<Const, const category, category>;
|
||||
using row_type = std::conditional_t<Const, const row, row>;
|
||||
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
using value_type = std::conditional_t<Const, const row_handle, row_handle>;
|
||||
using value_type = std::conditional_t<Const, const_row_handle, row_handle>;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
@@ -233,18 +234,18 @@ class iterator_impl_base<Const>
|
||||
|
||||
template <bool C>
|
||||
iterator_impl_base(const iterator_impl_base<C> &rhs)
|
||||
: m_current(const_cast<row_handle &>(rhs.m_current))
|
||||
: m_current(rhs.m_current)
|
||||
{
|
||||
}
|
||||
|
||||
iterator_impl_base(category_type &cat, row *current)
|
||||
iterator_impl_base(category_type &cat, row_type *current)
|
||||
: m_current(cat, *current)
|
||||
{
|
||||
}
|
||||
|
||||
template <bool C>
|
||||
iterator_impl_base(const iterator_impl_base<C> &rhs, const std::array<uint16_t, 0> &)
|
||||
: m_current(const_cast<row_handle &>(rhs.m_current))
|
||||
: m_current(rhs.m_current)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -276,7 +277,7 @@ class iterator_impl_base<Const>
|
||||
return &m_current;
|
||||
}
|
||||
|
||||
operator const row_handle() const
|
||||
operator const_row_handle() const
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
@@ -324,7 +325,7 @@ class iterator_impl_base<Const>
|
||||
/** @endcond */
|
||||
|
||||
private:
|
||||
row_handle m_current;
|
||||
value_type m_current;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -368,7 +369,7 @@ class iterator_impl_base<Const, T>
|
||||
|
||||
template <bool C>
|
||||
iterator_impl_base(iterator_impl_base<C, T> &rhs)
|
||||
: m_current(const_cast<row_handle&>(rhs.m_current))
|
||||
: m_current(rhs.m_current)
|
||||
, m_value(rhs.m_value)
|
||||
, m_item_ix(rhs.m_item_ix)
|
||||
{
|
||||
@@ -377,7 +378,7 @@ class iterator_impl_base<Const, T>
|
||||
|
||||
template <bool C>
|
||||
iterator_impl_base(const iterator_impl_base<C> &rhs, const std::array<uint16_t, 1> &cix)
|
||||
: m_current(const_cast<row_handle&>(rhs.m_current))
|
||||
: m_current(rhs.m_current)
|
||||
, m_item_ix(cix[0])
|
||||
{
|
||||
m_value = get();
|
||||
@@ -413,7 +414,7 @@ class iterator_impl_base<Const, T>
|
||||
return &m_value;
|
||||
}
|
||||
|
||||
operator const row_handle() const
|
||||
operator const_row_handle() const
|
||||
{
|
||||
return m_current;
|
||||
}
|
||||
@@ -460,7 +461,7 @@ class iterator_impl_base<Const, T>
|
||||
private:
|
||||
[[nodiscard]] value_type get() const
|
||||
{
|
||||
return m_current ? m_current[m_item_ix].template as<value_type>() : value_type{};
|
||||
return m_current ? m_current[m_item_ix].template get<value_type>() : value_type{};
|
||||
}
|
||||
|
||||
row_handle m_current;
|
||||
@@ -810,6 +811,11 @@ void swap(conditional_iterator_proxy_base<Const, Ts...> &lhs, conditional_iterat
|
||||
std::swap(lhs.mCix, rhs.mCix);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
// template <bool Const, typename... Ts>
|
||||
|
||||
|
||||
/** @endcond */
|
||||
|
||||
} // namespace cif
|
||||
|
||||
@@ -128,7 +128,7 @@ class atom
|
||||
return m_cat[{ { .name = "id", .value = m_id } }];
|
||||
}
|
||||
|
||||
[[nodiscard]] const row_handle row() const
|
||||
[[nodiscard]] const_row_handle row() const
|
||||
{
|
||||
return m_cat[{ { .name = "id", .value = m_id } }];
|
||||
}
|
||||
@@ -142,7 +142,7 @@ class atom
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] const row_handle row_aniso() const
|
||||
[[nodiscard]] const_row_handle row_aniso() const
|
||||
{
|
||||
row_handle result{};
|
||||
auto cat = m_db.get("atom_site_anisotrop");
|
||||
@@ -189,7 +189,7 @@ class atom
|
||||
* @param db The datablock where the _atom_site category resides
|
||||
* @param row The row containing the data for this atom
|
||||
*/
|
||||
atom(const datablock &db, const row_handle &row)
|
||||
atom(const datablock &db, const_row_handle &row)
|
||||
: atom(std::make_shared<atom_impl>(db, row["id"].as<std::string>()))
|
||||
{
|
||||
}
|
||||
@@ -315,10 +315,10 @@ class atom
|
||||
}
|
||||
|
||||
/// for direct access to underlying data, be careful!
|
||||
[[nodiscard]] const row_handle get_row() const { return impl().row(); }
|
||||
[[nodiscard]] const_row_handle get_row() const { return impl().row(); }
|
||||
|
||||
/// for direct access to underlying data, be careful!
|
||||
[[nodiscard]] const row_handle get_row_aniso() const { return impl().row_aniso(); }
|
||||
[[nodiscard]] const_row_handle get_row_aniso() const { return impl().row_aniso(); }
|
||||
|
||||
/// Return if the atom is actually a symmetry copy or the original one
|
||||
[[nodiscard]] bool is_symmetry_copy() const { return impl().m_symop != "1_555"; }
|
||||
|
||||
@@ -166,7 +166,13 @@ class sac_parser
|
||||
SAVE_NAME,
|
||||
STOP,
|
||||
ITEM_NAME,
|
||||
VALUE
|
||||
|
||||
VALUE_INAPPLICABLE,
|
||||
VALUE_UNKNOWN,
|
||||
VALUE_NUMERIC_INTEGER,
|
||||
VALUE_NUMERIC_FLOAT,
|
||||
VALUE_CHARSTRING,
|
||||
VALUE_TEXTFIELD
|
||||
};
|
||||
|
||||
static constexpr const char *get_token_name(CIFToken token)
|
||||
@@ -182,7 +188,15 @@ class sac_parser
|
||||
case CIFToken::SAVE_NAME: return "SAVE+name";
|
||||
case CIFToken::STOP: return "STOP";
|
||||
case CIFToken::ITEM_NAME: return "Tag";
|
||||
case CIFToken::VALUE: return "Value";
|
||||
// case CIFToken::VALUE: return "Value";
|
||||
|
||||
case CIFToken::VALUE_INAPPLICABLE: return "Inapplicable value";
|
||||
case CIFToken::VALUE_UNKNOWN: return "'Unknown' value (=null)";
|
||||
case CIFToken::VALUE_NUMERIC_INTEGER: return "Integer value";
|
||||
case CIFToken::VALUE_NUMERIC_FLOAT: return "Float value";
|
||||
case CIFToken::VALUE_CHARSTRING: return "Charstring value";
|
||||
case CIFToken::VALUE_TEXTFIELD: return "Textfield value";
|
||||
|
||||
default: return "Invalid token parameter";
|
||||
}
|
||||
}
|
||||
@@ -282,13 +296,17 @@ class sac_parser
|
||||
ItemName,
|
||||
TextItem,
|
||||
TextItemNL,
|
||||
Reserved,
|
||||
Value,
|
||||
|
||||
TextItemBS,
|
||||
TextItemBS2,
|
||||
TextItemBSNL,
|
||||
|
||||
Reserved,
|
||||
Value
|
||||
Numeric_Integer,
|
||||
Numeric_Float,
|
||||
Numeric_Exponent1,
|
||||
Numeric_Exponent2
|
||||
};
|
||||
|
||||
std::streambuf &m_source;
|
||||
@@ -302,6 +320,8 @@ class sac_parser
|
||||
// token buffer
|
||||
std::vector<char> m_token_buffer;
|
||||
std::string_view m_token_value;
|
||||
int64_t m_token_value_int;
|
||||
double m_token_value_float;
|
||||
|
||||
/** @endcond */
|
||||
};
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <initializer_list>
|
||||
#include <stdexcept>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
@@ -88,12 +89,13 @@ namespace cif
|
||||
|
||||
class category;
|
||||
class row_handle;
|
||||
class const_row_handle;
|
||||
|
||||
namespace cql
|
||||
{
|
||||
struct connection_impl;
|
||||
}
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
@@ -103,7 +105,7 @@ namespace detail
|
||||
{
|
||||
static constexpr std::size_t N = sizeof...(C);
|
||||
|
||||
get_row_result(const row_handle &r, std::array<uint16_t, N> &&items)
|
||||
get_row_result(const const_row_handle &r, std::array<uint16_t, N> &&items)
|
||||
: m_row(r)
|
||||
, m_items(std::move(items))
|
||||
{
|
||||
@@ -127,7 +129,7 @@ namespace detail
|
||||
return std::tuple<Ts...>{ m_row[m_items[Is]].template get<Ts>()... };
|
||||
}
|
||||
|
||||
const row_handle &m_row;
|
||||
const const_row_handle &m_row;
|
||||
std::array<uint16_t, N> m_items;
|
||||
};
|
||||
|
||||
@@ -179,7 +181,9 @@ class row : public std::vector<item_value>
|
||||
*/
|
||||
item_value *get(uint16_t ix)
|
||||
{
|
||||
return ix < size() ? &data()[ix] : nullptr;
|
||||
if (ix >= size())
|
||||
resize(ix + 1);
|
||||
return &data()[ix];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -190,14 +194,14 @@ class row : public std::vector<item_value>
|
||||
return ix < size() ? &data()[ix] : nullptr;
|
||||
}
|
||||
|
||||
// private:
|
||||
// private:
|
||||
friend class category;
|
||||
friend class category_index;
|
||||
|
||||
template <bool, typename...>
|
||||
friend class iterator_impl_base;
|
||||
|
||||
void append(uint16_t ix, item_value &&iv)
|
||||
void append(uint16_t ix, item_value iv)
|
||||
{
|
||||
if (ix >= size())
|
||||
resize(ix + 1);
|
||||
@@ -221,7 +225,8 @@ class row_handle
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
friend struct item_handle;
|
||||
template <bool>
|
||||
friend struct item_handle_base;
|
||||
friend class category;
|
||||
friend class category_index;
|
||||
friend class row_initializer;
|
||||
@@ -230,24 +235,24 @@ class row_handle
|
||||
friend class iterator_impl_base;
|
||||
|
||||
row_handle() = default;
|
||||
virtual ~row_handle() = default;
|
||||
|
||||
row_handle(const row_handle &) = default;
|
||||
row_handle(row_handle &&) = default;
|
||||
|
||||
row_handle &operator=(const row_handle &) = default;
|
||||
row_handle &operator=(row_handle &&) = default;
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/// \brief constructor taking a category @a cat and a row @a r
|
||||
row_handle(const category &cat, const row &r)
|
||||
: m_category(const_cast<category *>(&cat))
|
||||
, m_row(const_cast<row *>(&r))
|
||||
row_handle(category &cat, row &r)
|
||||
: m_category(&cat)
|
||||
, m_row(&r)
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief return the category this row belongs to
|
||||
[[nodiscard]] const category &get_category() const
|
||||
[[nodiscard]] category &get_category() const
|
||||
{
|
||||
return *m_category;
|
||||
}
|
||||
@@ -270,58 +275,31 @@ class row_handle
|
||||
return not empty();
|
||||
}
|
||||
|
||||
/// \brief return the count of the items
|
||||
[[nodiscard]] size_t size() const { return m_row->size(); }
|
||||
|
||||
/// \brief return a cif::item_handle to the item in item @a item_ix
|
||||
item_handle operator[](uint16_t item_ix)
|
||||
{
|
||||
return empty() ? item_handle::s_null_item : item_handle(item_ix, *this);
|
||||
return { *m_category, *m_row, item_ix };
|
||||
}
|
||||
|
||||
/// \brief return a const cif::item_handle to the item in item @a item_ix
|
||||
const item_handle operator[](uint16_t item_ix) const
|
||||
/// \brief return a cif::item_handle to the item in item @a item_ix
|
||||
const_item_handle operator[](uint16_t item_ix) const
|
||||
{
|
||||
return empty() ? item_handle::s_null_item : item_handle(item_ix, const_cast<row_handle &>(*this));
|
||||
return { *m_category, *m_row, item_ix };
|
||||
}
|
||||
|
||||
/// \brief return a cif::item_handle to the item in the item named @a item_name
|
||||
item_handle operator[](std::string_view item_name)
|
||||
{
|
||||
return empty() ? item_handle::s_null_item : item_handle(add_item(item_name), *this);
|
||||
return { *m_category, *m_row, get_item_ix(item_name) };
|
||||
}
|
||||
|
||||
/// \brief return a const cif::item_handle to the item in the item named @a item_name
|
||||
const item_handle operator[](std::string_view item_name) const
|
||||
/// \brief return a cif::item_handle to the item in the item named @a item_name
|
||||
const_item_handle operator[](std::string_view item_name) const
|
||||
{
|
||||
return empty() ? item_handle::s_null_item : item_handle(get_item_ix(item_name), const_cast<row_handle &>(*this));
|
||||
}
|
||||
|
||||
/// \brief Return an object that can be used in combination with cif::tie
|
||||
/// to assign the values for the items @a items
|
||||
template <typename... C>
|
||||
[[nodiscard]] auto get(C... items) const
|
||||
{
|
||||
return detail::get_row_result<C...>(*this, { get_item_ix(items)... });
|
||||
}
|
||||
|
||||
/// \brief Return a tuple of values of types @a Ts for the items @a items
|
||||
template <typename... Ts, typename... C>
|
||||
std::tuple<Ts...> get(C... items) const
|
||||
requires(sizeof...(Ts) == sizeof...(C) and sizeof...(C) != 1)
|
||||
{
|
||||
return detail::get_row_result<Ts...>(*this, { get_item_ix(items)... });
|
||||
}
|
||||
|
||||
/// \brief Get the value of item @a item cast to type @a T
|
||||
template <typename T>
|
||||
T get(const char *item) const
|
||||
{
|
||||
return operator[](get_item_ix(item)).template get<T>();
|
||||
}
|
||||
|
||||
/// \brief Get the value of item @a item cast to type @a T
|
||||
template <typename T>
|
||||
[[nodiscard]] T get(std::string_view item) const
|
||||
{
|
||||
return operator[](get_item_ix(item)).template get<T>();
|
||||
return { *m_category, *m_row, get_item_ix(item_name) };
|
||||
}
|
||||
|
||||
/// \brief assign each of the items named in @a values to their respective value
|
||||
@@ -360,39 +338,185 @@ class row_handle
|
||||
|
||||
void assign(uint16_t item, item_value value, bool updateLinked, bool validate = true);
|
||||
|
||||
/// \brief Return an object that can be used in combination with cif::tie
|
||||
/// to assign the values for the items @a items
|
||||
template <typename... C>
|
||||
[[nodiscard]] auto get(C... items) const
|
||||
{
|
||||
return detail::get_row_result<C...>(*this, { get_item_ix(items)... });
|
||||
}
|
||||
|
||||
/// \brief Return a tuple of values of types @a Ts for the items @a items
|
||||
template <typename... Ts, typename... C>
|
||||
std::tuple<Ts...> get(C... items) const
|
||||
requires(sizeof...(Ts) == sizeof...(C) and sizeof...(C) != 1)
|
||||
{
|
||||
return detail::get_row_result<Ts...>(*this, { get_item_ix(items)... });
|
||||
}
|
||||
|
||||
/// \brief Get the value of item @a item cast to type @a T
|
||||
template <typename T>
|
||||
[[nodiscard]] T get(std::string_view item) const
|
||||
{
|
||||
return operator[](get_item_ix(item)).template get<T>();
|
||||
}
|
||||
|
||||
/// \brief compare two rows
|
||||
bool operator==(const row_handle &rhs) const { return m_category == rhs.m_category and m_row == rhs.m_row; }
|
||||
|
||||
/// \brief compare two rows
|
||||
bool operator!=(const row_handle &rhs) const { return m_category != rhs.m_category or m_row != rhs.m_row; }
|
||||
|
||||
private:
|
||||
protected:
|
||||
[[nodiscard]] uint16_t get_item_ix(std::string_view name) const;
|
||||
[[nodiscard]] std::string_view get_item_name(uint16_t ix) const;
|
||||
|
||||
uint16_t add_item(std::string_view name);
|
||||
|
||||
friend cql::connection_impl;
|
||||
|
||||
row *get_row()
|
||||
[[nodiscard]] auto get_row() const
|
||||
{
|
||||
return m_row;
|
||||
}
|
||||
|
||||
[[nodiscard]] const row *get_row() const
|
||||
{
|
||||
return m_row;
|
||||
}
|
||||
// void swap(uint16_t item, row_handle &r) noexcept(false);
|
||||
// {
|
||||
// if (not m_category)
|
||||
// throw std::runtime_error("uninitialized row");
|
||||
//
|
||||
// m_category->swap_item(item, *this, b);
|
||||
// }
|
||||
|
||||
category *m_category = nullptr;
|
||||
row *m_row = nullptr;
|
||||
|
||||
private:
|
||||
uint16_t add_item(std::string_view name);
|
||||
|
||||
void assign(const item &i, bool updateLinked)
|
||||
{
|
||||
assign(i.name(), i.value(), updateLinked);
|
||||
}
|
||||
};
|
||||
|
||||
void swap(uint16_t item, row_handle &r) noexcept(false);
|
||||
class const_row_handle
|
||||
{
|
||||
public:
|
||||
/** @cond */
|
||||
template <bool>
|
||||
friend struct item_handle_base;
|
||||
friend class category;
|
||||
friend class category_index;
|
||||
friend class row_initializer;
|
||||
|
||||
category *m_category = nullptr;
|
||||
row *m_row = nullptr;
|
||||
template <bool, typename...>
|
||||
friend class iterator_impl_base;
|
||||
|
||||
const_row_handle() = default;
|
||||
virtual ~const_row_handle() = default;
|
||||
|
||||
const_row_handle(const const_row_handle &) = default;
|
||||
const_row_handle(const_row_handle &&) = default;
|
||||
const_row_handle &operator=(const const_row_handle &) = default;
|
||||
const_row_handle &operator=(const_row_handle &&) = default;
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/// \brief constructor taking a category @a cat and a row @a r
|
||||
const_row_handle(const category &cat, const row &r)
|
||||
: m_category(&cat)
|
||||
, m_row(&r)
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief return the category this row belongs to
|
||||
[[nodiscard]] const category &get_category() const
|
||||
{
|
||||
return *m_category;
|
||||
}
|
||||
|
||||
/// \brief return the row ID
|
||||
[[nodiscard]] int64_t row_id() const
|
||||
{
|
||||
return reinterpret_cast<int64_t>(m_row);
|
||||
}
|
||||
|
||||
/// \brief Return true if the row is empty or uninitialised
|
||||
[[nodiscard]] bool empty() const
|
||||
{
|
||||
return m_category == nullptr or m_row == nullptr;
|
||||
}
|
||||
|
||||
/// \brief convenience method to test for empty()
|
||||
explicit operator bool() const
|
||||
{
|
||||
return not empty();
|
||||
}
|
||||
|
||||
/// \brief return the count of the items
|
||||
[[nodiscard]] size_t size() const { return m_row->size(); }
|
||||
|
||||
/// \brief return a cif::item_handle to the item in item @a item_ix
|
||||
const_item_handle operator[](uint16_t item_ix) const
|
||||
{
|
||||
return { *m_category, *m_row, item_ix };
|
||||
}
|
||||
|
||||
/// \brief return a cif::item_handle to the item in the item named @a item_name
|
||||
const_item_handle operator[](std::string_view item_name) const
|
||||
{
|
||||
return { *m_category, *m_row, get_item_ix(item_name) };
|
||||
}
|
||||
|
||||
/// \brief Return an object that can be used in combination with cif::tie
|
||||
/// to assign the values for the items @a items
|
||||
template <typename... C>
|
||||
[[nodiscard]] auto get(C... items) const
|
||||
{
|
||||
return detail::get_row_result<C...>(*this, { get_item_ix(items)... });
|
||||
}
|
||||
|
||||
/// \brief Return a tuple of values of types @a Ts for the items @a items
|
||||
template <typename... Ts, typename... C>
|
||||
std::tuple<Ts...> get(C... items) const
|
||||
requires(sizeof...(Ts) == sizeof...(C) and sizeof...(C) != 1)
|
||||
{
|
||||
return detail::get_row_result<Ts...>(*this, { get_item_ix(items)... });
|
||||
}
|
||||
|
||||
/// \brief Get the value of item @a item cast to type @a T
|
||||
template <typename T>
|
||||
[[nodiscard]] T get(std::string_view item) const
|
||||
{
|
||||
return operator[](get_item_ix(item)).template get<T>();
|
||||
}
|
||||
|
||||
/// \brief compare two rows
|
||||
bool operator==(const const_row_handle &rhs) const { return m_category == rhs.m_category and m_row == rhs.m_row; }
|
||||
|
||||
/// \brief compare two rows
|
||||
bool operator!=(const const_row_handle &rhs) const { return m_category != rhs.m_category or m_row != rhs.m_row; }
|
||||
|
||||
protected:
|
||||
[[nodiscard]] uint16_t get_item_ix(std::string_view name) const;
|
||||
[[nodiscard]] std::string_view get_item_name(uint16_t ix) const;
|
||||
|
||||
friend cql::connection_impl;
|
||||
|
||||
[[nodiscard]] auto get_row() const
|
||||
{
|
||||
return m_row;
|
||||
}
|
||||
|
||||
// void swap(uint16_t item, const_row_handle &r) noexcept(false);
|
||||
// {
|
||||
// if (not m_category)
|
||||
// throw std::runtime_error("uninitialized row");
|
||||
//
|
||||
// m_category->swap_item(item, *this, b);
|
||||
// }
|
||||
|
||||
const category *m_category = nullptr;
|
||||
const row *m_row = nullptr;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
@@ -433,7 +557,7 @@ class row_initializer : public std::vector<item>
|
||||
}
|
||||
|
||||
/// \brief constructor taking the values of an existing row
|
||||
row_initializer(row_handle rh);
|
||||
row_initializer(const_row_handle rh);
|
||||
|
||||
/// \brief set the value for item name @a name to @a value
|
||||
void set_value(std::string name, item_value value);
|
||||
|
||||
@@ -326,11 +326,13 @@ struct item_validator
|
||||
return iequals(m_item_name, rhs.m_item_name);
|
||||
}
|
||||
|
||||
/// @brief Validate the value in @a value for this item
|
||||
/// Will throw a std::system_error exception if it fails
|
||||
void operator()(std::string_view value) const;
|
||||
/// @brief Validate value @a value, throws if invalid
|
||||
void validate_value(const item_value &value) const;
|
||||
|
||||
/// @brief A more gentle version of value validation
|
||||
/// @brief Validate value @a value and return potential error in @a ec
|
||||
bool validate_value(const item_value &value, std::error_code &ec) const noexcept;
|
||||
|
||||
/// @brief Validate value @a value and return potential error in @a ec
|
||||
bool validate_value(std::string_view value, std::error_code &ec) const noexcept;
|
||||
};
|
||||
|
||||
|
||||
211
src/category.cpp
211
src/category.cpp
@@ -97,10 +97,11 @@ class row_comparator
|
||||
int d = 0;
|
||||
for (const auto &[k, f] : m_comparator)
|
||||
{
|
||||
std::string_view ka = rha[k].text();
|
||||
std::string_view kb = rhb[k].text();
|
||||
// std::string_view ka = rha[k].text();
|
||||
// std::string_view kb = rhb[k].text();
|
||||
|
||||
d = f(ka, kb);
|
||||
// d = f(ka, kb);
|
||||
d = rha[k].value().compare(rhb[k].value());
|
||||
|
||||
if (d != 0)
|
||||
break;
|
||||
@@ -109,33 +110,35 @@ class row_comparator
|
||||
return d;
|
||||
}
|
||||
|
||||
int operator()(const category &cat, const category::key_type &a, const row *b) const
|
||||
{
|
||||
assert(b);
|
||||
// int operator()(const category &cat, const category::key_type &a, const row *b) const
|
||||
// {
|
||||
// assert(b);
|
||||
|
||||
row_handle rhb(cat, *b);
|
||||
// row_handle rhb(cat, *b);
|
||||
|
||||
int d = 0;
|
||||
auto ai = a.begin();
|
||||
// int d = 0;
|
||||
// auto ai = a.begin();
|
||||
|
||||
for (const auto &[k, f] : m_comparator)
|
||||
{
|
||||
assert(ai != a.end());
|
||||
// for (const auto &[k, f] : m_comparator)
|
||||
// {
|
||||
// // assert(ai != a.end());
|
||||
|
||||
std::string_view ka = ai->value;
|
||||
std::string_view kb = rhb[k].text();
|
||||
// // std::string_view ka = ai->value;
|
||||
// // std::string_view kb = rhb[k].text();
|
||||
|
||||
if (not(ai->may_be_null and rhb[k].empty()))
|
||||
d = f(ka, kb);
|
||||
// // if (not(ai->may_be_null and rhb[k].empty()))
|
||||
// // d = f(ka, kb);
|
||||
|
||||
if (d != 0)
|
||||
break;
|
||||
// d = rha[k].value().compare(rhb[k].value());
|
||||
|
||||
++ai;
|
||||
}
|
||||
// if (d != 0)
|
||||
// break;
|
||||
|
||||
return d;
|
||||
}
|
||||
// ++ai;
|
||||
// }
|
||||
|
||||
// return d;
|
||||
// }
|
||||
|
||||
private:
|
||||
using compareFunc = std::function<int(std::string_view, std::string_view)>;
|
||||
@@ -368,34 +371,35 @@ row *category_index::find(const category &cat, row *k) const
|
||||
|
||||
row *category_index::find_by_value(const category &cat, const category::key_type &k) const
|
||||
{
|
||||
// sort the values in k first
|
||||
return nullptr;
|
||||
// // sort the values in k first
|
||||
|
||||
category::key_type k2;
|
||||
for (auto &f : cat.key_item_indices())
|
||||
{
|
||||
auto fld = cat.get_item_name(f);
|
||||
// category::key_type k2;
|
||||
// for (auto &f : cat.key_item_indices())
|
||||
// {
|
||||
// auto fld = cat.get_item_name(f);
|
||||
|
||||
auto ki = std::ranges::find_if(k, [&fld](auto &i)
|
||||
{ return i.name == fld; });
|
||||
if (ki == k.end())
|
||||
k2.emplace_back(std::string{ fld }, "");
|
||||
else
|
||||
k2.emplace_back(*ki);
|
||||
}
|
||||
// auto ki = std::ranges::find_if(k, [&fld](auto &i)
|
||||
// { return i.name == fld; });
|
||||
// if (ki == k.end())
|
||||
// k2.emplace_back(std::string{ fld }, "");
|
||||
// else
|
||||
// k2.emplace_back(*ki);
|
||||
// }
|
||||
|
||||
const entry *r = m_root;
|
||||
while (r != nullptr)
|
||||
{
|
||||
int d = m_row_comparator(cat, k2, r->m_row);
|
||||
if (d < 0)
|
||||
r = r->m_left;
|
||||
else if (d > 0)
|
||||
r = r->m_right;
|
||||
else
|
||||
break;
|
||||
}
|
||||
// const entry *r = m_root;
|
||||
// while (r != nullptr)
|
||||
// {
|
||||
// int d = m_row_comparator(cat, k2, r->m_row);
|
||||
// if (d < 0)
|
||||
// r = r->m_left;
|
||||
// else if (d > 0)
|
||||
// r = r->m_right;
|
||||
// else
|
||||
// break;
|
||||
// }
|
||||
|
||||
return r ? r->m_row : nullptr;
|
||||
// return r ? r->m_row : nullptr;
|
||||
}
|
||||
|
||||
void category_index::insert(category &cat, row *k)
|
||||
@@ -422,7 +426,7 @@ category_index::entry *category_index::insert(category &cat, entry *h, row *v)
|
||||
for (auto col : cat.key_items())
|
||||
{
|
||||
if (rh[col])
|
||||
os << col << ": " << std::quoted(rh[col].text()) << "; ";
|
||||
os << col << ": " << std::quoted(rh[col].str()) << "; ";
|
||||
}
|
||||
|
||||
throw duplicate_key_error("Duplicate Key violation, cat: " + cat.name() + " values: " + os.str());
|
||||
@@ -870,7 +874,7 @@ bool category::is_valid() const
|
||||
seen = true;
|
||||
std::error_code ec;
|
||||
|
||||
iv->validate_value(vi->text(), ec);
|
||||
iv->validate_value(*vi, ec);
|
||||
|
||||
if (ec != std::errc{})
|
||||
{
|
||||
@@ -990,6 +994,25 @@ row_handle category::operator[](const key_type &key)
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
const_row_handle category::operator[](const key_type &key) const
|
||||
{
|
||||
const_row_handle result{};
|
||||
|
||||
if (not empty())
|
||||
{
|
||||
if (m_index == nullptr)
|
||||
throw std::logic_error("Category " + m_name + " does not have an index");
|
||||
|
||||
auto row = m_index->find_by_value(*this, key);
|
||||
if (row != nullptr)
|
||||
result = { *this, *row };
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
condition category::get_parents_condition(row_handle rh, const category &parentCat) const
|
||||
{
|
||||
if (m_validator == nullptr or m_cat_validator == nullptr)
|
||||
@@ -1010,12 +1033,12 @@ condition category::get_parents_condition(row_handle rh, const category &parentC
|
||||
|
||||
for (std::size_t ix = 0; ix < link->m_child_keys.size(); ++ix)
|
||||
{
|
||||
auto childValue = rh[link->m_child_keys[ix]];
|
||||
auto childValue = rh[link->m_child_keys[ix]].value();
|
||||
|
||||
if (childValue.empty())
|
||||
continue;
|
||||
|
||||
cond = std::move(cond) and key(link->m_parent_keys[ix]) == childValue.text();
|
||||
cond = std::move(cond) and key(link->m_parent_keys[ix]) == childValue;
|
||||
}
|
||||
|
||||
result = std::move(result) or std::move(cond);
|
||||
@@ -1055,14 +1078,14 @@ condition category::get_children_condition(row_handle rh, const category &childC
|
||||
auto childKey = link->m_child_keys[ix];
|
||||
auto parentKey = link->m_parent_keys[ix];
|
||||
|
||||
auto parentValue = rh[parentKey];
|
||||
auto parentValue = rh[parentKey].value();
|
||||
|
||||
if (parentValue.empty())
|
||||
cond = std::move(cond) and key(childKey) == null;
|
||||
else if (link->m_parent_keys.size() > 1 and not mandatoryChildItems.contains(childKey))
|
||||
cond = std::move(cond) and (key(childKey) == parentValue.text() or key(childKey) == null);
|
||||
cond = std::move(cond) and (key(childKey) == parentValue or key(childKey) == null);
|
||||
else
|
||||
cond = std::move(cond) and key(childKey) == parentValue.text();
|
||||
cond = std::move(cond) and key(childKey) == parentValue;
|
||||
}
|
||||
|
||||
result = std::move(result) or std::move(cond);
|
||||
@@ -1405,7 +1428,7 @@ void category::update_value(const std::vector<row_handle> &rows, std::string_vie
|
||||
{
|
||||
for (auto row : rows)
|
||||
{
|
||||
std::string value{ value_provider(row[item_name].text()) };
|
||||
auto value{ value_provider(row[item_name].value()) };
|
||||
|
||||
std::error_code ec;
|
||||
col.m_validator->validate_value(value, ec);
|
||||
@@ -1417,8 +1440,8 @@ void category::update_value(const std::vector<row_handle> &rows, std::string_vie
|
||||
// update and see if we need to update any child categories that depend on this value
|
||||
for (auto parent : rows)
|
||||
{
|
||||
std::string oldValue{ parent[item_name].text() };
|
||||
std::string value{ value_provider(oldValue) };
|
||||
auto oldValue{ parent[item_name].value() };
|
||||
auto value{ value_provider(oldValue) };
|
||||
|
||||
update_value(parent.get_row(), colIx, value, false, false);
|
||||
|
||||
@@ -1441,7 +1464,7 @@ void category::update_value(const std::vector<row_handle> &rows, std::string_vie
|
||||
cond = std::move(cond) && key(ck) == oldValue;
|
||||
}
|
||||
else
|
||||
cond = std::move(cond) && key(ck) == parent[pk].text();
|
||||
cond = std::move(cond) && key(ck) == parent[pk].value();
|
||||
}
|
||||
|
||||
auto children = childCat->find(std::move(cond));
|
||||
@@ -1465,7 +1488,7 @@ void category::update_value(const std::vector<row_handle> &rows, std::string_vie
|
||||
std::string pk = linked->m_parent_keys[ix];
|
||||
std::string ck = linked->m_child_keys[ix];
|
||||
|
||||
cond_c = std::move(cond_c) && key(pk) == child[ck].text();
|
||||
cond_c = std::move(cond_c) && key(pk) == child[ck].value();
|
||||
}
|
||||
|
||||
auto parents = find(std::move(cond_c));
|
||||
@@ -1486,7 +1509,7 @@ void category::update_value(const std::vector<row_handle> &rows, std::string_vie
|
||||
if (pk == item_name)
|
||||
check = std::move(check) && key(ck) == value;
|
||||
else
|
||||
check = std::move(check) && key(ck) == parent[pk].text();
|
||||
check = std::move(check) && key(ck) == parent[pk].value();
|
||||
}
|
||||
|
||||
if (childCat->contains(std::move(check))) // phew..., narrow escape
|
||||
@@ -1527,11 +1550,13 @@ void category::update_value(row *row, uint16_t item, item_value value, bool upda
|
||||
if (ival != nullptr and *ival == value)
|
||||
return;
|
||||
|
||||
auto oldValue = *ival;
|
||||
|
||||
m_dirty = true;
|
||||
|
||||
// check the value
|
||||
if (col.m_validator and validate)
|
||||
col.m_validator->operator()(value);
|
||||
col.m_validator->validate_value(value);
|
||||
|
||||
// If the item is part of the Key for this category, remove it from the index
|
||||
// before updating
|
||||
@@ -1580,11 +1605,11 @@ void category::update_value(row *row, uint16_t item, item_value value, bool upda
|
||||
if (pk == iv->m_item_name)
|
||||
{
|
||||
childItemName = ck;
|
||||
cond = std::move(cond) and key(ck) == oldStrValue;
|
||||
cond = std::move(cond) and key(ck) == oldValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string_view pk_value = rh[pk].text();
|
||||
auto pk_value = rh[pk].value();
|
||||
if (pk_value.empty())
|
||||
cond = std::move(cond) and key(ck) == null;
|
||||
else
|
||||
@@ -1616,7 +1641,7 @@ void category::update_value(row *row, uint16_t item, item_value value, bool upda
|
||||
cond_n = std::move(cond_n) and key(ck) == value;
|
||||
else
|
||||
{
|
||||
std::string_view pk_value = rh[pk].text();
|
||||
auto pk_value = rh[pk].value();
|
||||
if (pk_value.empty())
|
||||
cond_n = std::move(cond_n) and key(ck) == null;
|
||||
else
|
||||
@@ -1651,7 +1676,7 @@ row *category::clone_row(const row &r)
|
||||
if (not i)
|
||||
continue;
|
||||
|
||||
result->append(ix, { i.text() });
|
||||
result->append(ix, i);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
@@ -1684,7 +1709,7 @@ row_handle category::create_copy(row_handle r)
|
||||
{
|
||||
auto i = r.m_row->get(ix);
|
||||
if (i != nullptr)
|
||||
items.emplace_back(m_items[ix].m_name, i->text());
|
||||
items.emplace_back(m_items[ix].m_name, *i);
|
||||
}
|
||||
|
||||
if (m_cat_validator and m_cat_validator->m_keys.size() == 1)
|
||||
@@ -1742,7 +1767,7 @@ category::iterator category::insert_impl(const_iterator pos, row *n)
|
||||
auto i = n->get(ix);
|
||||
if (i != nullptr)
|
||||
{
|
||||
iv->operator()(i->value());
|
||||
iv->validate_value(*i);
|
||||
seen = true;
|
||||
}
|
||||
|
||||
@@ -2055,11 +2080,11 @@ void category::write_cif(std::ostream &os, const std::vector<uint16_t> &order, b
|
||||
if (v == nullptr)
|
||||
continue;
|
||||
|
||||
if (v->text().find('\n') == std::string_view::npos)
|
||||
if (v->str().find('\n') == std::string_view::npos)
|
||||
{
|
||||
std::size_t l = v->text().length();
|
||||
std::size_t l = v->str().length();
|
||||
|
||||
if (not sac_parser::is_unquoted_string(v->text()))
|
||||
if (not sac_parser::is_unquoted_string(v->str()))
|
||||
l += 2;
|
||||
|
||||
if (l > 132)
|
||||
@@ -2079,10 +2104,10 @@ void category::write_cif(std::ostream &os, const std::vector<uint16_t> &order, b
|
||||
{
|
||||
std::size_t w = itemWidths[cix];
|
||||
|
||||
std::string_view s;
|
||||
std::string s;
|
||||
auto iv = r->get(cix);
|
||||
if (iv != nullptr)
|
||||
s = iv->text();
|
||||
s = iv->str();
|
||||
|
||||
if (s.empty())
|
||||
s = "?";
|
||||
@@ -2134,10 +2159,10 @@ void category::write_cif(std::ostream &os, const std::vector<uint16_t> &order, b
|
||||
if (not right_aligned[cix])
|
||||
continue;
|
||||
|
||||
std::string_view s;
|
||||
std::string s;
|
||||
auto iv = m_head->get(cix);
|
||||
if (iv != nullptr)
|
||||
s = iv->text();
|
||||
s = iv->str();
|
||||
|
||||
if (s.empty())
|
||||
s = "?";
|
||||
@@ -2160,10 +2185,10 @@ void category::write_cif(std::ostream &os, const std::vector<uint16_t> &order, b
|
||||
os << m_name << '.';
|
||||
os << col.m_name << std::string(l - col.m_name.length() - m_name.length() - 2, ' ');
|
||||
|
||||
std::string_view s;
|
||||
std::string s;
|
||||
auto iv = m_head->get(cix);
|
||||
if (iv != nullptr)
|
||||
s = iv->text();
|
||||
s = iv->str();
|
||||
|
||||
if (s.empty())
|
||||
s = "?";
|
||||
@@ -2262,7 +2287,7 @@ void category::write_delimited(std::ostream &os, const std::vector<uint16_t> &or
|
||||
if (v == nullptr)
|
||||
continue;
|
||||
|
||||
size_t l = get_line(v->text()).length();
|
||||
size_t l = get_line(v->str()).length();
|
||||
if (itemWidths[ix] < l)
|
||||
itemWidths[ix] = l;
|
||||
}
|
||||
@@ -2324,11 +2349,11 @@ void category::write_delimited(std::ostream &os, const std::vector<uint16_t> &or
|
||||
|
||||
std::size_t w = itemWidths[cix];
|
||||
|
||||
std::string_view s;
|
||||
std::string s;
|
||||
auto iv = r->get(cix);
|
||||
|
||||
if (iv != nullptr)
|
||||
s = iv->text();
|
||||
s = iv->str();
|
||||
|
||||
if (s == "?" or s == ".")
|
||||
s = "";
|
||||
@@ -2383,7 +2408,7 @@ void category::write_markdown(std::ostream &os, const std::vector<uint16_t> &ord
|
||||
if (v == nullptr)
|
||||
continue;
|
||||
|
||||
size_t l = v->text().length();
|
||||
size_t l = v->str().length();
|
||||
if (itemWidths[ix] < l)
|
||||
itemWidths[ix] = l;
|
||||
}
|
||||
@@ -2432,11 +2457,11 @@ void category::write_markdown(std::ostream &os, const std::vector<uint16_t> &ord
|
||||
|
||||
std::size_t w = itemWidths[cix];
|
||||
|
||||
std::string_view s;
|
||||
std::string s;
|
||||
auto iv = r->get(cix);
|
||||
|
||||
if (iv != nullptr)
|
||||
s = iv->text();
|
||||
s = iv->str();
|
||||
|
||||
if (s == "?" or s == ".")
|
||||
s = "";
|
||||
@@ -2509,7 +2534,7 @@ void category::write_table(std::ostream &os, const std::vector<uint16_t> &order,
|
||||
if (v == nullptr)
|
||||
continue;
|
||||
|
||||
size_t l = v->text().length();
|
||||
size_t l = v->str().length();
|
||||
if (itemWidths[ix] < l)
|
||||
itemWidths[ix] = l;
|
||||
}
|
||||
@@ -2565,11 +2590,11 @@ void category::write_table(std::ostream &os, const std::vector<uint16_t> &order,
|
||||
|
||||
std::size_t w = itemWidths[cix];
|
||||
|
||||
std::string_view s;
|
||||
std::string s;
|
||||
auto iv = r->get(cix);
|
||||
|
||||
if (iv != nullptr)
|
||||
s = iv->text();
|
||||
s = iv->str();
|
||||
|
||||
if (s == "?" or s == ".")
|
||||
s = "";
|
||||
@@ -2664,7 +2689,7 @@ bool category::operator==(const category &rhs) const
|
||||
// a.reorderByIndex();
|
||||
// b.reorderByIndex();
|
||||
|
||||
auto rowEqual = [&](const row_handle &a, const row_handle &b)
|
||||
auto rowEqual = [&](const_row_handle &a, const_row_handle &b)
|
||||
{
|
||||
int d = 0;
|
||||
|
||||
@@ -2675,7 +2700,7 @@ bool category::operator==(const category &rhs) const
|
||||
|
||||
std::tie(item_name, compare) = item_names[kix];
|
||||
|
||||
d = compare(a[item_name].text(), b[item_name].text());
|
||||
d = a[item_name].compare(b[item_name]);
|
||||
|
||||
if (d != 0)
|
||||
break;
|
||||
@@ -2706,14 +2731,14 @@ bool category::operator==(const category &rhs) const
|
||||
|
||||
// make it an option to compare unapplicable to empty or something
|
||||
|
||||
auto ta = ra[item_name].text();
|
||||
if (ta == "." or ta == "?")
|
||||
ta = "";
|
||||
auto tb = rb[item_name].text();
|
||||
if (tb == "." or tb == "?")
|
||||
tb = "";
|
||||
// auto ta = ra[item_name].text();
|
||||
// if (ta == "." or ta == "?")
|
||||
// ta = "";
|
||||
// auto tb = rb[item_name].text();
|
||||
// if (tb == "." or tb == "?")
|
||||
// tb = "";
|
||||
|
||||
if (compare(ta, tb) != 0)
|
||||
if (ra[item_name].compare(rb[item_name]) != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -567,9 +567,9 @@ compound *local_compound_factory_impl::construct_compound(const datablock &rdb,
|
||||
{ "atom_id", atom_id },
|
||||
{ "type_symbol", type_symbol },
|
||||
{ "charge", charge },
|
||||
{ "model_Cartn_x", x.has_value() ? x : xi, 3 },
|
||||
{ "model_Cartn_y", y.has_value() ? y : yi, 3 },
|
||||
{ "model_Cartn_z", z.has_value() ? z : zi, 3 },
|
||||
{ "model_Cartn_x", x.has_value() ? x : xi/* , 3 */ },
|
||||
{ "model_Cartn_y", y.has_value() ? y : yi/* , 3 */ },
|
||||
{ "model_Cartn_z", z.has_value() ? z : zi/* , 3 */ },
|
||||
{ "pdbx_ordinal", ord++ } });
|
||||
|
||||
formal_charge += charge;
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace detail
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
// bool test(row_handle r) const override
|
||||
// bool test(const_row_handle r) const override
|
||||
// {
|
||||
// return m_single_hit == r;
|
||||
// }
|
||||
@@ -126,21 +126,6 @@ namespace detail
|
||||
return this;
|
||||
}
|
||||
|
||||
condition_impl *key_equals_number_condition_impl::prepare(const category &c)
|
||||
{
|
||||
m_item_ix = c.get_item_ix(m_item_name);
|
||||
|
||||
if (c.get_cat_validator() != nullptr and
|
||||
c.key_item_indices().contains(m_item_ix) and
|
||||
c.key_item_indices().size() == 1)
|
||||
{
|
||||
item v(m_item_name, m_value);
|
||||
m_single_hit = c[{ { m_item_name, std::string{ v.value() }, false } }];
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
bool found_in_range(condition_impl *c, std::vector<and_condition_impl *>::iterator b, std::vector<and_condition_impl *>::iterator e)
|
||||
{
|
||||
bool result = true;
|
||||
@@ -237,17 +222,6 @@ namespace detail
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto s = dynamic_cast<const key_equals_number_condition_impl *>(sub); s != nullptr)
|
||||
{
|
||||
if (keys.contains(s->m_item_name))
|
||||
{
|
||||
item v{ s->m_item_name, s->m_value };
|
||||
lookup.emplace_back(s->m_item_name, std::string{ v.value() });
|
||||
subs.emplace_back(sub);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto s = dynamic_cast<const key_equals_or_empty_condition_impl *>(sub); s != nullptr)
|
||||
{
|
||||
if (keys.contains(s->m_item_name))
|
||||
@@ -258,17 +232,6 @@ namespace detail
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto s = dynamic_cast<const key_equals_number_or_empty_condition_impl *>(sub); s != nullptr)
|
||||
{
|
||||
if (keys.contains(s->m_item_name))
|
||||
{
|
||||
item v{ s->m_item_name, s->m_value };
|
||||
lookup.emplace_back(s->m_item_name, std::string{ v.value() }, true);
|
||||
subs.emplace_back(sub);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (lookup.size() == keys.size())
|
||||
@@ -283,7 +246,7 @@ namespace detail
|
||||
return this;
|
||||
}
|
||||
|
||||
bool and_condition_impl::test(row_handle r) const
|
||||
bool and_condition_impl::test(const_row_handle r) const
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ class dictionary_parser : public parser
|
||||
match(CIFToken::ITEM_NAME);
|
||||
}
|
||||
|
||||
while (m_lookahead == CIFToken::VALUE)
|
||||
while (m_lookahead >= CIFToken::VALUE_INAPPLICABLE)
|
||||
{
|
||||
cat->emplace({});
|
||||
auto row = cat->back();
|
||||
@@ -164,7 +164,7 @@ class dictionary_parser : public parser
|
||||
for (auto item_name : item_names)
|
||||
{
|
||||
row[item_name] = m_token_value;
|
||||
match(CIFToken::VALUE);
|
||||
match(m_lookahead);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ class dictionary_parser : public parser
|
||||
cat->emplace({});
|
||||
cat->back()[item_name] = m_token_value;
|
||||
|
||||
match(CIFToken::VALUE);
|
||||
match(m_lookahead >= CIFToken::VALUE_INAPPLICABLE ? m_lookahead : CIFToken::VALUE_CHARSTRING);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,7 +257,7 @@ class dictionary_parser : public parser
|
||||
|
||||
auto vi = std::ranges::find(ivs, item_validator{ item_name });
|
||||
if (vi == ivs.end())
|
||||
ivs.emplace_back(item_name, iequals(mandatory, "yes"), tv, ess, defaultValue, cat_name, aliases);
|
||||
ivs.push_back(item_validator{ item_name, iequals(mandatory, "yes"), tv, ess, defaultValue, cat_name, std::move(aliases) });
|
||||
else
|
||||
{
|
||||
// need to update the itemValidator?
|
||||
|
||||
78
src/item.cpp
78
src/item.cpp
@@ -36,38 +36,70 @@
|
||||
namespace cif
|
||||
{
|
||||
|
||||
const item_handle item_handle::s_null_item;
|
||||
row_handle s_null_row_handle;
|
||||
|
||||
item_handle::item_handle() noexcept
|
||||
: m_item_ix(std::numeric_limits<uint16_t>::max())
|
||||
, m_row_handle(s_null_row_handle)
|
||||
int item_value::compare(const item_value &b, bool ignore_case) const noexcept
|
||||
{
|
||||
}
|
||||
int d = static_cast<int>(m_data.m_type) - static_cast<int>(b.m_data.m_type);
|
||||
|
||||
std::string_view item_handle::text() const
|
||||
{
|
||||
if (not m_row_handle.empty())
|
||||
if (d == 0)
|
||||
{
|
||||
auto iv = m_row_handle.m_row->get(m_item_ix);
|
||||
if (iv != nullptr)
|
||||
return iv->text();
|
||||
switch (m_data.m_type)
|
||||
{
|
||||
case cif::item_value_type::BOOLEAN:
|
||||
d = static_cast<int>(m_data.m_value.m_boolean) - static_cast<int>(b.m_data.m_value.m_boolean);
|
||||
break;
|
||||
case cif::item_value_type::INT:
|
||||
d = m_data.m_value.m_integer - b.m_data.m_value.m_integer;
|
||||
break;
|
||||
case cif::item_value_type::FLOAT:
|
||||
{
|
||||
auto dp = (m_data.m_value.m_float <=> b.m_data.m_value.m_float);
|
||||
if (dp == std::partial_ordering::less)
|
||||
d = -1;
|
||||
else if (dp == std::partial_ordering::greater)
|
||||
d = 1;
|
||||
break;
|
||||
}
|
||||
case cif::item_value_type::TEXT:
|
||||
d = m_data.sv().compare(b.m_data.sv());
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
return d;
|
||||
}
|
||||
|
||||
void item_handle::assign_value(std::string_view value)
|
||||
{
|
||||
assert(not m_row_handle.empty());
|
||||
m_row_handle.assign(m_item_ix, value, true);
|
||||
}
|
||||
// void const_item_handle::assign_value(const item_value &value)
|
||||
// {
|
||||
// assert(not m_row_handle.empty());
|
||||
// m_row_handle.assign(m_item_ix, value, true);
|
||||
// }
|
||||
|
||||
void item_handle::swap(item_handle &b)
|
||||
std::ostream &operator<<(std::ostream &os, const item_value &v)
|
||||
{
|
||||
assert(m_item_ix == b.m_item_ix);
|
||||
// assert(&m_row_handle.m_category == &b.m_row_handle.m_category);
|
||||
m_row_handle.swap(m_item_ix, b.m_row_handle);
|
||||
switch (v.type())
|
||||
{
|
||||
case cif::item_value_type::BOOLEAN:
|
||||
os << std::boolalpha << v.m_data.m_value.m_boolean;
|
||||
break;
|
||||
case cif::item_value_type::INT:
|
||||
os << v.m_data.m_value.m_integer;
|
||||
break;
|
||||
case cif::item_value_type::FLOAT:
|
||||
os << v.m_data.m_value.m_float;
|
||||
break;
|
||||
case cif::item_value_type::TEXT:
|
||||
os << v.m_data.sv();
|
||||
break;
|
||||
case cif::item_value_type::MISSING:
|
||||
os << '?';
|
||||
break;
|
||||
case cif::item_value_type::INAPPLICABLE:
|
||||
os << '.';
|
||||
break;
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace cif
|
||||
|
||||
@@ -237,7 +237,7 @@ atom residue::create_new_atom(atom_type inType, const std::string &inAtomID, poi
|
||||
{ "auth_atom_id", inAtomID },
|
||||
{ "auth_comp_id", m_compound_id },
|
||||
{ "auth_seq_id", m_pdb_seq_num },
|
||||
{ "occupancy", 1.0f, 2 },
|
||||
{ "occupancy", 1.0f/* , 2 */ },
|
||||
{ "B_iso_or_equiv", 20.0f },
|
||||
{ "pdbx_PDB_model_num", m_structure->get_model_nr() },
|
||||
});
|
||||
@@ -955,8 +955,8 @@ cif::mm::atom sugar::add_atom(row_initializer atom_info)
|
||||
atom_info.set_value({ "auth_asym_id", m_branch->get_asym_id() });
|
||||
atom_info.set_value({ "auth_comp_id", m_compound_id });
|
||||
atom_info.set_value({ "auth_seq_id", m_pdb_seq_num });
|
||||
atom_info.set_value({ "occupancy", 1.0, 2 });
|
||||
atom_info.set_value({ "B_iso_or_equiv", 30.0, 2 });
|
||||
atom_info.set_value({ "occupancy", 1.0/* , 2 */ });
|
||||
atom_info.set_value({ "B_iso_or_equiv", 30.0/* , 2 */ });
|
||||
atom_info.set_value({ "pdbx_PDB_model_num", 1 });
|
||||
|
||||
auto row = atom_site.emplace(std::move(atom_info));
|
||||
@@ -1859,11 +1859,7 @@ void structure::swap_atoms(atom a1, atom a2)
|
||||
auto r2 = atomSites.find1(key("id") == a2.id());
|
||||
|
||||
for (std::string fld : std::initializer_list<std::string>{ "label_atom_id", "auth_atom_id", "type_symbol" })
|
||||
{
|
||||
auto l1 = r1[fld];
|
||||
auto l2 = r2[fld];
|
||||
l1.swap(l2);
|
||||
}
|
||||
swap(r1[fld].value(), r2[fld].value());
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
@@ -2280,7 +2276,7 @@ std::string structure::create_non_poly(const std::string &entity_id, std::vector
|
||||
atom.set_value_if_empty({ "auth_seq_id", 1 });
|
||||
atom.set_value_if_empty({ "pdbx_PDB_model_num", 1 });
|
||||
atom.set_value_if_empty({ "label_alt_id", "" });
|
||||
atom.set_value_if_empty({ "occupancy", 1.0, 2 });
|
||||
atom.set_value_if_empty({ "occupancy", 1.0/* , 2 */ });
|
||||
|
||||
auto row = atom_site.emplace(atom.begin(), atom.end());
|
||||
|
||||
@@ -2378,7 +2374,7 @@ void structure::create_water(row_initializer atom)
|
||||
atom.set_value_if_empty({ "auth_comp_id", "HOH" });
|
||||
atom.set_value_if_empty({ "pdbx_PDB_model_num", 1 });
|
||||
atom.set_value_if_empty({ "label_alt_id", "" });
|
||||
atom.set_value_if_empty({ "occupancy", 1.0, 2 });
|
||||
atom.set_value_if_empty({ "occupancy", 1.0/* , 2 */ });
|
||||
|
||||
auto row = atom_site.emplace(atom.begin(), atom.end());
|
||||
|
||||
@@ -2449,7 +2445,7 @@ std::string structure::create_link(atom a1, atom a2, const std::string &link_typ
|
||||
{ "ptnr2_auth_seq_id", a2.get_auth_seq_id() },
|
||||
{ "ptnr2_symmetry", a2.symmetry() },
|
||||
|
||||
{ "pdbx_dist_value", distance(a1.get_location(), a2.get_location()), 3 },
|
||||
{ "pdbx_dist_value", distance(a1.get_location(), a2.get_location())/* , 3 */ },
|
||||
{ "pdbx_role", role } });
|
||||
|
||||
return link_id;
|
||||
|
||||
163
src/parser.cpp
163
src/parser.cpp
@@ -276,6 +276,8 @@ sac_parser::CIFToken sac_parser::get_next_token()
|
||||
m_token_buffer.clear();
|
||||
m_token_value = {};
|
||||
|
||||
bool negative = false;
|
||||
|
||||
reserved_words_automaton dag;
|
||||
|
||||
while (result == CIFToken::UNKNOWN)
|
||||
@@ -314,6 +316,15 @@ sac_parser::CIFToken sac_parser::get_next_token()
|
||||
}
|
||||
else if (dag.move(ch) == reserved_words_automaton::undefined)
|
||||
state = State::Reserved;
|
||||
else if (ch == '+' or ch == '-')
|
||||
{
|
||||
negative = true;
|
||||
state = State::Numeric_Integer;
|
||||
}
|
||||
else if (ch >= '0' and ch <= '9')
|
||||
state = State::Numeric_Integer;
|
||||
else if (ch == '.')
|
||||
state = State::Numeric_Float;
|
||||
else
|
||||
state = State::Value;
|
||||
break;
|
||||
@@ -350,7 +361,7 @@ sac_parser::CIFToken sac_parser::get_next_token()
|
||||
if (not is_non_blank(ch))
|
||||
{
|
||||
retract();
|
||||
result = CIFToken::VALUE;
|
||||
result = CIFToken::VALUE_UNKNOWN;
|
||||
}
|
||||
else
|
||||
state = State::Value;
|
||||
@@ -396,7 +407,7 @@ sac_parser::CIFToken sac_parser::get_next_token()
|
||||
{
|
||||
assert(m_token_buffer.size() >= 2);
|
||||
m_token_value = std::string_view(m_token_buffer.data() + 1, m_token_buffer.size() - 3);
|
||||
result = CIFToken::VALUE;
|
||||
result = CIFToken::VALUE_CHARSTRING;
|
||||
}
|
||||
else if (ch == kEOF)
|
||||
error("unterminated textfield");
|
||||
@@ -411,7 +422,7 @@ sac_parser::CIFToken sac_parser::get_next_token()
|
||||
{
|
||||
assert(m_token_buffer.size() >= 2);
|
||||
m_token_value = std::string_view(m_token_buffer.data() + 1, m_token_buffer.size() - 3);
|
||||
result = CIFToken::VALUE;
|
||||
result = CIFToken::VALUE_TEXTFIELD;
|
||||
}
|
||||
else if (ch == kEOF)
|
||||
error("unterminated textfield");
|
||||
@@ -432,7 +443,7 @@ sac_parser::CIFToken sac_parser::get_next_token()
|
||||
if (is_white(ch))
|
||||
{
|
||||
retract();
|
||||
result = CIFToken::VALUE;
|
||||
result = CIFToken::VALUE_CHARSTRING;
|
||||
if (m_token_buffer.size() < 2)
|
||||
error("Invalid quoted string token");
|
||||
|
||||
@@ -467,7 +478,7 @@ sac_parser::CIFToken sac_parser::get_next_token()
|
||||
if (not is_non_blank(ch))
|
||||
{
|
||||
retract();
|
||||
result = CIFToken::VALUE;
|
||||
result = CIFToken::VALUE_CHARSTRING;
|
||||
m_token_value = std::string_view(m_token_buffer.data(), m_token_buffer.size());
|
||||
}
|
||||
else
|
||||
@@ -508,11 +519,65 @@ sac_parser::CIFToken sac_parser::get_next_token()
|
||||
}
|
||||
break;
|
||||
|
||||
case State::Numeric_Integer:
|
||||
if (ch == '.')
|
||||
state = State::Numeric_Float;
|
||||
else if (ch == 'e' or ch == 'E')
|
||||
state = State::Numeric_Exponent1;
|
||||
else if (not is_non_blank(ch))
|
||||
{
|
||||
retract();
|
||||
result = CIFToken::VALUE_NUMERIC_INTEGER;
|
||||
}
|
||||
else if (ch < '0' or ch > '9')
|
||||
state = State::Value;
|
||||
break;
|
||||
|
||||
case State::Numeric_Float:
|
||||
if (not is_non_blank(ch))
|
||||
{
|
||||
retract();
|
||||
if (m_token_buffer.size() == 1)
|
||||
result = CIFToken::VALUE_INAPPLICABLE;
|
||||
else
|
||||
result = CIFToken::VALUE_NUMERIC_FLOAT;
|
||||
}
|
||||
else if (ch == 'e' or ch == 'E')
|
||||
state = State::Numeric_Exponent1;
|
||||
else if (ch < '0' or ch > '9')
|
||||
state = State::Value;
|
||||
break;
|
||||
|
||||
case State::Numeric_Exponent1:
|
||||
if (ch == '+' or ch == '-' or (ch >= '0' and ch <= '9'))
|
||||
state = State::Numeric_Exponent2;
|
||||
else
|
||||
{
|
||||
if (VERBOSE > 0)
|
||||
std::cerr << "parsing " << std::string_view{ m_token_buffer.data(), m_token_buffer.size() } << " Invalid floating point value, expected digit or sign character\n";
|
||||
state = State::Value;
|
||||
}
|
||||
break;
|
||||
|
||||
case State::Numeric_Exponent2:
|
||||
if (not is_non_blank(ch))
|
||||
{
|
||||
retract();
|
||||
result = CIFToken::VALUE_NUMERIC_FLOAT;
|
||||
}
|
||||
else if (ch < '0' or ch > '9')
|
||||
{
|
||||
if (VERBOSE > 0)
|
||||
std::cerr << "parsing " << std::string_view{ m_token_buffer.data(), m_token_buffer.size() } << " Invalid floating point value, expected exponent digit\n";
|
||||
state = State::Value;
|
||||
}
|
||||
break;
|
||||
|
||||
case State::Value:
|
||||
if (not is_non_blank(ch))
|
||||
{
|
||||
retract();
|
||||
result = CIFToken::VALUE;
|
||||
result = CIFToken::VALUE_CHARSTRING;
|
||||
m_token_value = std::string_view(m_token_buffer.data(), m_token_buffer.size());
|
||||
break;
|
||||
}
|
||||
@@ -525,12 +590,25 @@ sac_parser::CIFToken sac_parser::get_next_token()
|
||||
}
|
||||
}
|
||||
|
||||
if (VERBOSE >= 5)
|
||||
// if (VERBOSE >= 5)
|
||||
// {
|
||||
// std::cerr << get_token_name(result);
|
||||
// if (result != CIFToken::END_OF_FILE)
|
||||
// std::cerr << " " << std::quoted(m_token_value);
|
||||
// std::cerr << '\n';
|
||||
// }
|
||||
|
||||
if (result == CIFToken::VALUE_NUMERIC_INTEGER)
|
||||
{
|
||||
std::cerr << get_token_name(result);
|
||||
if (result != CIFToken::END_OF_FILE)
|
||||
std::cerr << " " << std::quoted(m_token_value);
|
||||
std::cerr << '\n';
|
||||
auto [ptr, ec] = std::from_chars(m_token_buffer.data(), m_token_buffer.data() + m_token_buffer.size(), m_token_value_int);
|
||||
if (ec != std::errc{})
|
||||
error("Invalid integer value: " + std::make_error_code(ec).message());
|
||||
}
|
||||
else if (result == CIFToken::VALUE_NUMERIC_FLOAT)
|
||||
{
|
||||
auto [ptr, ec] = std::from_chars(m_token_buffer.data(), m_token_buffer.data() + m_token_buffer.size(), m_token_value_float);
|
||||
if (ec != std::errc{})
|
||||
error("Invalid integer value: " + std::make_error_code(ec).message());
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -785,7 +863,10 @@ void sac_parser::parse_global()
|
||||
while (m_lookahead == CIFToken::ITEM_NAME)
|
||||
{
|
||||
match(CIFToken::ITEM_NAME);
|
||||
match(CIFToken::VALUE);
|
||||
if (m_lookahead >= CIFToken::VALUE_INAPPLICABLE)
|
||||
match(m_lookahead);
|
||||
else
|
||||
match(CIFToken::VALUE_CHARSTRING);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -824,14 +905,38 @@ void sac_parser::parse_datablock()
|
||||
match(CIFToken::ITEM_NAME);
|
||||
}
|
||||
|
||||
while (m_lookahead == CIFToken::VALUE)
|
||||
while (m_lookahead >= CIFToken::VALUE_INAPPLICABLE)
|
||||
{
|
||||
produce_row();
|
||||
|
||||
for (auto item_name : item_names)
|
||||
{
|
||||
produce_item(cat, item_name, m_token_value);
|
||||
match(CIFToken::VALUE);
|
||||
switch (m_lookahead)
|
||||
{
|
||||
case CIFToken::VALUE_INAPPLICABLE:
|
||||
produce_item(cat, item_name, nullptr);
|
||||
match(m_lookahead);
|
||||
break;
|
||||
case CIFToken::VALUE_UNKNOWN:
|
||||
produce_item(cat, item_name, std::optional<std::string>{});
|
||||
match(m_lookahead);
|
||||
break;
|
||||
case CIFToken::VALUE_NUMERIC_INTEGER:
|
||||
produce_item(cat, item_name, m_token_value_int);
|
||||
match(m_lookahead);
|
||||
break;
|
||||
case CIFToken::VALUE_NUMERIC_FLOAT:
|
||||
produce_item(cat, item_name, m_token_value_float);
|
||||
match(m_lookahead);
|
||||
break;
|
||||
case CIFToken::VALUE_CHARSTRING:
|
||||
case CIFToken::VALUE_TEXTFIELD:
|
||||
produce_item(cat, item_name, m_token_value);
|
||||
match(m_lookahead);
|
||||
break;
|
||||
default:;
|
||||
match(CIFToken::VALUE_CHARSTRING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -853,9 +958,33 @@ void sac_parser::parse_datablock()
|
||||
|
||||
match(CIFToken::ITEM_NAME);
|
||||
|
||||
produce_item(cat, itemName, m_token_value);
|
||||
switch (m_lookahead)
|
||||
{
|
||||
case CIFToken::VALUE_INAPPLICABLE:
|
||||
produce_item(cat, itemName, nullptr);
|
||||
match(CIFToken::VALUE_INAPPLICABLE);
|
||||
break;
|
||||
case CIFToken::VALUE_UNKNOWN:
|
||||
produce_item(cat, itemName, item_value{ std::optional<std::string>{} });
|
||||
match(CIFToken::VALUE_UNKNOWN);
|
||||
break;
|
||||
case CIFToken::VALUE_NUMERIC_INTEGER:
|
||||
produce_item(cat, itemName, m_token_value_int);
|
||||
match(CIFToken::VALUE_NUMERIC_INTEGER);
|
||||
break;
|
||||
case CIFToken::VALUE_NUMERIC_FLOAT:
|
||||
produce_item(cat, itemName, m_token_value_float);
|
||||
match(CIFToken::VALUE_NUMERIC_FLOAT);
|
||||
break;
|
||||
case CIFToken::VALUE_CHARSTRING:
|
||||
case CIFToken::VALUE_TEXTFIELD:
|
||||
produce_item(cat, itemName, m_token_value);
|
||||
match(m_lookahead);
|
||||
break;
|
||||
default:
|
||||
match(CIFToken::VALUE_CHARSTRING);
|
||||
}
|
||||
|
||||
match(CIFToken::VALUE);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -652,9 +652,9 @@ class FBase
|
||||
mRow = r.front();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string_view text() const
|
||||
[[nodiscard]] std::string text() const
|
||||
{
|
||||
return mRow.empty() or mRow[mField].empty() ? "" : mRow[mField].text();
|
||||
return mRow.empty() or mRow[mField].empty() ? "" : mRow[mField].str();
|
||||
}
|
||||
|
||||
row_handle mRow;
|
||||
|
||||
@@ -4566,7 +4566,7 @@ void PDBFileParser::ConstructEntities()
|
||||
{ "id", cc },
|
||||
{ "name", name },
|
||||
{ "formula", formula },
|
||||
{ "formula_weight", formulaWeight, 3 },
|
||||
{ "formula_weight", formulaWeight/* , 3 */ },
|
||||
{ "mon_nstd_flag", nstd },
|
||||
{ "type", type }
|
||||
});
|
||||
|
||||
@@ -1534,7 +1534,7 @@ bool Remark3Parser::parse(const std::string &expMethod, PDBRecord *r, cif::datab
|
||||
continue;
|
||||
|
||||
for (auto &iv : cv->m_item_validators)
|
||||
r2[iv.m_item_name] = r1[iv.m_item_name].text();
|
||||
r2[iv.m_item_name] = r1[iv.m_item_name].str();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
|
||||
#include "cif++.hpp"
|
||||
#include "cif++/compound.hpp"
|
||||
#include "cif++/cql.hpp"
|
||||
// #include "cif++/cql.hpp"
|
||||
#include "cif++/item.hpp"
|
||||
#include "cif++/point.hpp"
|
||||
#include "cif++/row.hpp"
|
||||
|
||||
@@ -187,7 +188,7 @@ void checkEntities(datablock &db)
|
||||
}
|
||||
|
||||
if (formula_weight > 0)
|
||||
entity.assign({ { "formula_weight", formula_weight, 3 } });
|
||||
entity.assign({ { "formula_weight", formula_weight/* , 3 */ } });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,10 +455,10 @@ void checkChemCompRecords(datablock &db)
|
||||
|
||||
for (auto chem_comp_entry : chem_comp)
|
||||
{
|
||||
auto compound = cf.create(chem_comp_entry["id"].text());
|
||||
auto compound = cf.create(chem_comp_entry["id"].str());
|
||||
|
||||
if (not compound)
|
||||
std::cerr << "Unknown compound: " << chem_comp_entry["id"].text() << '\n';
|
||||
std::cerr << "Unknown compound: " << chem_comp_entry["id"].str() << '\n';
|
||||
else
|
||||
{
|
||||
std::vector<item> items;
|
||||
@@ -544,7 +545,7 @@ void checkAtomRecords(datablock &db)
|
||||
if (row["type_symbol"].empty())
|
||||
throw std::runtime_error("Missing type symbol in atom_site record");
|
||||
|
||||
std::string symbol{ row["type_symbol"].text() };
|
||||
std::string symbol{ row["type_symbol"].str() };
|
||||
if (atom_type.count("symbol"_key == symbol) == 0)
|
||||
atom_type.emplace({ { "symbol", symbol } });
|
||||
|
||||
@@ -617,19 +618,19 @@ void checkAtomRecords(datablock &db)
|
||||
row["label_seq_id"] = std::to_string(seq_id);
|
||||
|
||||
if (row["label_asym_id"].empty())
|
||||
row["label_asym_id"] = row["auth_asym_id"].text();
|
||||
row["label_asym_id"] = row["auth_asym_id"].value();
|
||||
else if (row["auth_asym_id"].empty())
|
||||
row["auth_asym_id"] = row["label_asym_id"].text();
|
||||
row["auth_asym_id"] = row["label_asym_id"].value();
|
||||
|
||||
if (row["label_comp_id"].empty())
|
||||
row["label_comp_id"] = row["auth_comp_id"].text();
|
||||
row["label_comp_id"] = row["auth_comp_id"].value();
|
||||
else if (row["auth_comp_id"].empty())
|
||||
row["auth_comp_id"] = row["label_comp_id"].text();
|
||||
row["auth_comp_id"] = row["label_comp_id"].value();
|
||||
|
||||
if (row["label_atom_id"].empty())
|
||||
row["label_atom_id"] = row["auth_atom_id"].text();
|
||||
row["label_atom_id"] = row["auth_atom_id"].value();
|
||||
else if (row["auth_atom_id"].empty())
|
||||
row["auth_atom_id"] = row["label_atom_id"].text();
|
||||
row["auth_atom_id"] = row["label_atom_id"].value();
|
||||
|
||||
// Rewrite the coordinates and other items that look better in a fixed format
|
||||
// Be careful not to nuke invalidly formatted data here
|
||||
@@ -648,14 +649,14 @@ void checkAtomRecords(datablock &db)
|
||||
if (auto [ptr, ec] = cif::from_chars(s.data(), s.data() + s.length(), v); ec != std::errc{})
|
||||
continue;
|
||||
|
||||
if (s.length() < prec + 1UL or s[s.length() - prec - 1] != '.')
|
||||
/* if (s.length() < prec + 1UL or s[s.length() - prec - 1] != '.')
|
||||
{
|
||||
char b[12];
|
||||
|
||||
if (auto [ptr, ec] = std::to_chars(b, b + sizeof(b), v, std::chars_format::fixed, prec); ec == std::errc{})
|
||||
row.assign(item_name, { b, static_cast<std::string::size_type>(ptr - b) }, false, false);
|
||||
}
|
||||
}
|
||||
*/ }
|
||||
}
|
||||
|
||||
// auto *cv = atom_site.get_cat_validator();
|
||||
@@ -714,24 +715,24 @@ void checkAtomAnisotropRecords(datablock &db)
|
||||
// this happens sometimes (Phenix):
|
||||
|
||||
if (row["type_symbol"].empty())
|
||||
row["type_symbol"] = parent["type_symbol"].text();
|
||||
else if (row["type_symbol"].text() != parent["type_symbol"].text())
|
||||
row["type_symbol"] = parent["type_symbol"].value();
|
||||
else if (row["type_symbol"].value() != parent["type_symbol"].value())
|
||||
{
|
||||
if (cif::VERBOSE and std::exchange(warnReplaceTypeSymbol, false))
|
||||
std::clog << "Replacing type_symbol in atom_site_anisotrop record(s)\n";
|
||||
row["type_symbol"] = parent["type_symbol"].text();
|
||||
row["type_symbol"] = parent["type_symbol"].value();
|
||||
}
|
||||
|
||||
if (row["pdbx_auth_alt_id"].empty() and not parent["pdbx_auth_alt_id"].empty())
|
||||
row["pdbx_auth_alt_id"] = parent["pdbx_auth_alt_id"].text();
|
||||
row["pdbx_auth_alt_id"] = parent["pdbx_auth_alt_id"].value();
|
||||
if (row["pdbx_label_seq_id"].empty() and not parent["label_seq_id"].empty())
|
||||
row["pdbx_label_seq_id"] = parent["label_seq_id"].text();
|
||||
row["pdbx_label_seq_id"] = parent["label_seq_id"].value();
|
||||
if (row["pdbx_label_asym_id"].empty() and not parent["label_asym_id"].empty())
|
||||
row["pdbx_label_asym_id"] = parent["label_asym_id"].text();
|
||||
row["pdbx_label_asym_id"] = parent["label_asym_id"].value();
|
||||
if (row["pdbx_label_atom_id"].empty() and not parent["label_atom_id"].empty())
|
||||
row["pdbx_label_atom_id"] = parent["label_atom_id"].text();
|
||||
row["pdbx_label_atom_id"] = parent["label_atom_id"].value();
|
||||
if (row["pdbx_label_comp_id"].empty() and not parent["label_comp_id"].empty())
|
||||
row["pdbx_label_comp_id"] = parent["label_comp_id"].text();
|
||||
row["pdbx_label_comp_id"] = parent["label_comp_id"].value();
|
||||
}
|
||||
|
||||
if (not to_be_deleted.empty())
|
||||
@@ -1130,7 +1131,7 @@ void createPdbxPolySeqScheme(datablock &db)
|
||||
for (auto col : { "label_asym_id", "label_entity_id", "label_seq_id", "label_comp_id", "auth_seq_id", "auth_comp_id", "pdbx_PDB_ins_code"})
|
||||
atom_site.add_item(col);
|
||||
|
||||
cql::connection conn(db);
|
||||
/* cql::connection conn(db);
|
||||
cql::transaction tx(conn);
|
||||
for (auto &&[asym_id, entity_id, seq_id, comp_id, auth_seq_id, auth_comp_id, pdb_ins_code] :
|
||||
tx.stream<std::string, std::string, std::optional<int>, std::string, std::string, std::string, std::optional<std::string>>(
|
||||
@@ -1165,7 +1166,7 @@ void createPdbxPolySeqScheme(datablock &db)
|
||||
last_asym_id = asym_id;
|
||||
last_seq_id = seq_id;
|
||||
}
|
||||
|
||||
*/
|
||||
// // select distinct A.entity_id, A.id, B.mon_id, B.num, B.hetero, C.auth_seq_id, C.auth_comp_id, C.pdbx_PDB_ins_code from struct_asym A, entity_poly_seq B, atom_site C where A.entity_id = B.entity_id and C.label_asym_id = A.id and C.label_seq_id = B.num order by A.entity_id, B.num;
|
||||
|
||||
// // select distinct label_entity_id, label_asym_id, label_comp_id, label_seq_id, auth_asym_id, auth_seq_id, auth_comp_id from atom_site order by CAST(label_entity_id AS INT), label_asym_id, CAST(label_seq_id AS INT);
|
||||
@@ -1658,14 +1659,13 @@ bool reconstruct_pdbx(file &file, const validator &validator)
|
||||
for (auto row : cat)
|
||||
{
|
||||
std::error_code ec;
|
||||
std::string_view value = row[ix].text();
|
||||
|
||||
if (not iv->validate_value(value, ec))
|
||||
if (not iv->validate_value(row[ix].value(), ec))
|
||||
{
|
||||
if (cif::VERBOSE > 0)
|
||||
std::clog << "Replacing value (" << std::quoted(value) << ") for item " << item_name << " in category " << cat.name() << " since it does not validate\n";
|
||||
std::clog << "Replacing value (" << std::quoted(row[ix].str()) << ") for item " << item_name << " in category " << cat.name() << " since it does not validate\n";
|
||||
|
||||
row[ix] = "?";
|
||||
row[ix] = item_value{ cif::item_value_type::INAPPLICABLE };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ condition get_parents_condition(const validator &validator, row_handle rh, const
|
||||
if (childValue.empty())
|
||||
continue;
|
||||
|
||||
cond = std::move(cond) and key(link->m_parent_keys[ix]) == childValue.text();
|
||||
cond = std::move(cond) and key(link->m_parent_keys[ix]) == childValue.value();
|
||||
}
|
||||
|
||||
result = std::move(result) or std::move(cond);
|
||||
@@ -145,7 +145,7 @@ bool is_valid_pdbx_file(const file &file, const validator &validator, std::error
|
||||
if (p.size() != 1)
|
||||
{
|
||||
if (VERBOSE > 0)
|
||||
std::clog << "In atom_site record: " << r["id"].text() << '\n';
|
||||
std::clog << "In atom_site record: " << r["id"].str() << '\n';
|
||||
throw std::runtime_error("For each monomer in atom_site there should be exactly one pdbx_poly_seq_scheme record");
|
||||
}
|
||||
}
|
||||
|
||||
82
src/row.cpp
82
src/row.cpp
@@ -40,37 +40,25 @@
|
||||
namespace cif
|
||||
{
|
||||
|
||||
item_value s_null_item;
|
||||
// item_value &row_handle::operator[](uint16_t item_ix)
|
||||
// {
|
||||
// return empty() or item_ix >= m_row->size() ? s_null_item : m_row->operator[](item_ix);
|
||||
// }
|
||||
|
||||
item_value &row_handle::operator[](uint16_t item_ix)
|
||||
{
|
||||
return empty() or item_ix >= m_row->size() ? s_null_item : m_row->operator[](item_ix);
|
||||
}
|
||||
// const item_value &row_handle::operator[](uint16_t item_ix) const
|
||||
// {
|
||||
// return empty() or item_ix >= m_row->size() ? s_null_item : m_row->operator[](item_ix);
|
||||
// }
|
||||
|
||||
const item_value &row_handle::operator[](uint16_t item_ix) const
|
||||
{
|
||||
return empty() or item_ix >= m_row->size() ? s_null_item : m_row->operator[](item_ix);
|
||||
}
|
||||
// item_value &row_handle::operator[](std::string_view item_name)
|
||||
// {
|
||||
// return operator[](get_item_ix(item_name));
|
||||
// }
|
||||
|
||||
item_value &row_handle::operator[](std::string_view item_name)
|
||||
{
|
||||
return operator[](get_item_ix(item_name));
|
||||
}
|
||||
|
||||
const item_value &row_handle::operator[](std::string_view item_name) const
|
||||
{
|
||||
return operator[](get_item_ix(item_name));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
void row_handle::assign(uint16_t item, item_value value, bool updateLinked, bool validate)
|
||||
{
|
||||
if (not m_category)
|
||||
throw std::runtime_error("uninitialized row");
|
||||
|
||||
m_category->update_value(m_row, item, std::move(value), updateLinked, validate);
|
||||
}
|
||||
// const item_value &row_handle::operator[](std::string_view item_name) const
|
||||
// {
|
||||
// return operator[](get_item_ix(item_name));
|
||||
// }
|
||||
|
||||
uint16_t row_handle::get_item_ix(std::string_view name) const
|
||||
{
|
||||
@@ -88,6 +76,32 @@ std::string_view row_handle::get_item_name(uint16_t ix) const
|
||||
return m_category->get_item_name(ix);
|
||||
}
|
||||
|
||||
uint16_t const_row_handle::get_item_ix(std::string_view name) const
|
||||
{
|
||||
if (not m_category)
|
||||
throw std::runtime_error("uninitialized row");
|
||||
|
||||
return m_category->get_item_ix(name);
|
||||
}
|
||||
|
||||
std::string_view const_row_handle::get_item_name(uint16_t ix) const
|
||||
{
|
||||
if (not m_category)
|
||||
throw std::runtime_error("uninitialized row");
|
||||
|
||||
return m_category->get_item_name(ix);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
void row_handle::assign(uint16_t item, item_value value, bool updateLinked, bool validate)
|
||||
{
|
||||
if (not m_category)
|
||||
throw std::runtime_error("uninitialized row");
|
||||
|
||||
m_category->update_value(m_row, item, std::move(value), updateLinked, validate);
|
||||
}
|
||||
|
||||
uint16_t row_handle::add_item(std::string_view name)
|
||||
{
|
||||
if (not m_category)
|
||||
@@ -96,24 +110,16 @@ uint16_t row_handle::add_item(std::string_view name)
|
||||
return m_category->add_item(name);
|
||||
}
|
||||
|
||||
void row_handle::swap(uint16_t item, row_handle &b)
|
||||
{
|
||||
if (not m_category)
|
||||
throw std::runtime_error("uninitialized row");
|
||||
|
||||
m_category->swap_item(item, *this, b);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
row_initializer::row_initializer(row_handle rh)
|
||||
row_initializer::row_initializer(const_row_handle rh)
|
||||
{
|
||||
if (not rh.m_category)
|
||||
throw std::runtime_error("uninitialized row");
|
||||
|
||||
assert(rh.m_row);
|
||||
|
||||
row *r = rh.get_row();
|
||||
auto r = rh.get_row();
|
||||
auto &cat = *rh.m_category;
|
||||
|
||||
for (uint16_t ix = 0; ix < r->size(); ++ix)
|
||||
|
||||
@@ -257,22 +257,22 @@ int type_validator::compare(std::string_view a, std::string_view b) const
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
void item_validator::operator()(std::string_view value) const
|
||||
void item_validator::validate_value(const item_value &value) const
|
||||
{
|
||||
std::error_code ec;
|
||||
if (not validate_value(value, ec))
|
||||
throw std::system_error(ec, std::format("'{}' is not a valid value for {}", value, m_item_name));
|
||||
throw std::system_error(ec, std::format("'{}' is not a valid value for {}", value.str(), m_item_name));
|
||||
}
|
||||
|
||||
bool item_validator::validate_value(std::string_view value, std::error_code &ec) const noexcept
|
||||
bool item_validator::validate_value(const item_value &value, std::error_code &ec) const noexcept
|
||||
{
|
||||
ec.clear();
|
||||
|
||||
if (not value.empty() and value != "?" and value != ".")
|
||||
if (not value.empty())
|
||||
{
|
||||
if (m_type != nullptr and not m_type->m_rx->match(value))
|
||||
if (m_type != nullptr and not m_type->m_rx->match(value.str()))
|
||||
ec = make_error_code(validation_error::value_does_not_match_rx);
|
||||
else if (not m_enums.empty() and m_enums.count(std::string{ value }) == 0)
|
||||
else if (not m_enums.empty() and m_enums.count(value.str()) == 0)
|
||||
ec = make_error_code(validation_error::value_is_not_in_enumeration_list);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user