Skip to content

Commit

Permalink
Fix query generation when using constant numeric values
Browse files Browse the repository at this point in the history
replace size_t with std::size_t to silence warnings
  • Loading branch information
mhekkel committed Apr 3, 2024
1 parent 66717fe commit 588e075
Show file tree
Hide file tree
Showing 36 changed files with 515 additions and 288 deletions.
4 changes: 2 additions & 2 deletions include/cif++/atom_type.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ enum class radius_type
};

/// @brief The number of radii per element which can be requested from atom_type_info
constexpr size_t kRadiusTypeCount = static_cast<size_t>(radius_type::type_count);
constexpr std::size_t kRadiusTypeCount = static_cast<std::size_t>(radius_type::type_count);

/// An enum used to select either the effective or the crystal radius of an ion.
/// See explanation on Wikipedia: https://en.wikipedia.org/wiki/Ionic_radius
Expand Down Expand Up @@ -276,7 +276,7 @@ class atom_type_traits
{
if (type >= radius_type::type_count)
throw std::invalid_argument("invalid radius requested");
return m_info->radii[static_cast<size_t>(type)] / 100.f;
return m_info->radii[static_cast<std::size_t>(type)] / 100.f;
}

/// \brief Return the radius for a charged version of this atom in a solid crystal
Expand Down
14 changes: 7 additions & 7 deletions include/cif++/category.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -293,15 +293,15 @@ class category
}

/// Return a count of the rows in this container
size_t size() const
std::size_t size() const
{
return std::distance(cbegin(), cend());
}

/// Return the theoretical maximum number or rows that can be stored
size_t max_size() const
std::size_t max_size() const
{
return std::numeric_limits<size_t>::max(); // this is a bit optimistic, I guess
return std::numeric_limits<std::size_t>::max(); // this is a bit optimistic, I guess
}

/// Return true if the category is empty
Expand Down Expand Up @@ -831,9 +831,9 @@ class category
/// @brief Return the total number of rows that match condition @a cond
/// @param cond The condition to match
/// @return The count
size_t count(condition &&cond) const
std::size_t count(condition &&cond) const
{
size_t result = 0;
std::size_t result = 0;

if (cond)
{
Expand Down Expand Up @@ -903,14 +903,14 @@ class category
/// @brief Erase all rows that match condition @a cond
/// @param cond The condition
/// @return The number of rows that have been erased
size_t erase(condition &&cond);
std::size_t erase(condition &&cond);

/// @brief Erase all rows that match condition @a cond calling
/// the visitor function @a visit for each before actually erasing it.
/// @param cond The condition
/// @param visit The visitor function
/// @return The number of rows that have been erased
size_t erase(condition &&cond, std::function<void(row_handle)> &&visit);
std::size_t erase(condition &&cond, std::function<void(row_handle)> &&visit);

/// @brief Emplace the values in @a ri in a new row
/// @param ri An object containing the values to insert
Expand Down
217 changes: 204 additions & 13 deletions include/cif++/condition.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "cif++/row.hpp"

#include <cassert>
#include <concepts>
#include <functional>
#include <iostream>
#include <regex>
Expand Down Expand Up @@ -470,6 +471,106 @@ namespace detail
std::optional<row_handle> m_single_hit;
};

struct key_equals_number_condition_impl : public condition_impl
{
key_equals_number_condition_impl(const std::string &name, double v)
: m_item_name(name)
, m_value(v)
{
}

condition_impl *prepare(const category &c) override;

bool test(row_handle r) const override
{
return m_single_hit.has_value() ? *m_single_hit == r : r[m_item_ix].compare(m_value) == 0;
}

void str(std::ostream &os) const override
{
os << m_item_name << " == " << m_value;
}

virtual std::optional<row_handle> single() const override
{
return m_single_hit;
}

virtual bool equals(const condition_impl *rhs) const override
{
if (typeid(*rhs) == typeid(key_equals_number_condition_impl))
{
auto ri = static_cast<const key_equals_number_condition_impl *>(rhs);
if (m_single_hit.has_value() or ri->m_single_hit.has_value())
return m_single_hit == ri->m_single_hit;
else
// watch out, both m_item_ix might be the same while item_names might be diffent (in case they both do not exist in the category)
return m_item_ix == ri->m_item_ix and m_value == ri->m_value and m_item_name == ri->m_item_name;
}
return this == rhs;
}

std::string m_item_name;
uint16_t m_item_ix = 0;
double m_value;
std::optional<row_handle> m_single_hit;
};

struct key_equals_number_or_empty_condition_impl : public condition_impl
{
key_equals_number_or_empty_condition_impl(key_equals_number_condition_impl *equals)
: m_item_name(equals->m_item_name)
, m_value(equals->m_value)
, m_single_hit(equals->m_single_hit)
{
}

condition_impl *prepare(const category &c) override
{
m_item_ix = get_item_ix(c, m_item_name);
return this;
}

bool test(row_handle r) const override
{
bool result = false;
if (m_single_hit.has_value())
result = *m_single_hit == r;
else
result = r[m_item_ix].empty() or r[m_item_ix].compare(m_value) == 0;
return result;
}

void str(std::ostream &os) const override
{
os << '(' << m_item_name << " == " << m_value << " OR " << m_item_name << " IS NULL)";
}

virtual std::optional<row_handle> single() const override
{
return m_single_hit;
}

virtual bool equals(const condition_impl *rhs) const override
{
if (typeid(*rhs) == typeid(key_equals_number_or_empty_condition_impl))
{
auto ri = static_cast<const key_equals_number_or_empty_condition_impl *>(rhs);
if (m_single_hit.has_value() or ri->m_single_hit.has_value())
return m_single_hit == ri->m_single_hit;
else
// watch out, both m_item_ix might be the same while item_names might be diffent (in case they both do not exist in the category)
return m_item_ix == ri->m_item_ix and m_value == ri->m_value and m_item_name == ri->m_item_name;
}
return this == rhs;
}

std::string m_item_name;
uint16_t m_item_ix = 0;
double m_value;
std::optional<row_handle> m_single_hit;
};

struct key_compare_condition_impl : public condition_impl
{
template <typename COMP>
Expand Down Expand Up @@ -876,7 +977,8 @@ inline condition operator or(condition &&a, condition &&b)
if (ci->m_item_name == ce->m_item_name)
return condition(new detail::key_equals_or_empty_condition_impl(ci));
}
else if (typeid(*b.m_impl) == typeid(detail::key_equals_condition_impl) and

if (typeid(*b.m_impl) == typeid(detail::key_equals_condition_impl) and
typeid(*a.m_impl) == typeid(detail::key_is_empty_condition_impl))
{
auto ci = static_cast<detail::key_equals_condition_impl *>(b.m_impl);
Expand All @@ -886,6 +988,26 @@ 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)));
}

Expand Down Expand Up @@ -959,13 +1081,16 @@ 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 value @a v
* @brief Operator to create an equals condition based on a key @a key and a numeric value @a v
*/
template <typename T>
template <Numeric T>
condition operator==(const key &key, const T &v)
{
return condition(new detail::key_equals_condition_impl({ key.m_item_name, v }));
return condition(new detail::key_equals_number_condition_impl(key.m_item_name, v));
}

/**
Expand All @@ -979,6 +1104,16 @@ 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
*/
Expand All @@ -999,60 +1134,116 @@ inline condition operator!=(const key &key, std::string_view value)
/**
* @brief Operator to create a greater than condition based on a key @a key and a value @a v
*/
template <typename T>
template <Numeric T>
condition operator>(const key &key, const T &v)
{
std::ostringstream s;
s << " > " << 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)
{ return r[item_name].template compare<T>(v, icase) > 0; },
{ return r[item_name].compare(v) > 0; },
s.str()));
}

/**
* @brief Operator to create a greater than or equals condition based on a key @a key and a value @a v
*/
template <typename T>
template <Numeric T>
condition operator>=(const key &key, const T &v)
{
std::ostringstream s;
s << " >= " << 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)
{ return r[item_name].template compare<T>(v, icase) >= 0; },
{ return r[item_name].compare(v) >= 0; },
s.str()));
}

/**
* @brief Operator to create a less than condition based on a key @a key and a value @a v
*/
template <typename T>
template <Numeric T>
condition operator<(const key &key, const T &v)
{
std::ostringstream s;
s << " < " << 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)
{ return r[item_name].template compare<T>(v, icase) < 0; },
{ return r[item_name].compare(v) < 0; },
s.str()));
}

/**
* @brief Operator to create a less than or equals condition based on a key @a key and a value @a v
*/
template <typename T>
template <Numeric T>
condition operator<=(const key &key, const T &v)
{
std::ostringstream s;
s << " <= " << 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)
{ return r[item_name].template compare<T>(v, icase) <= 0; },
{ return r[item_name].compare(v) <= 0; },
s.str()));
}

/**
* @brief Operator to create a greater than condition based on a key @a key and a value @a v
*/
inline condition operator>(const key &key, std::string_view v)
{
std::ostringstream s;
s << " > " << 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)
{ return r[item_name].compare(v, icase) > 0; },
s.str()));
}

/**
* @brief Operator to create a greater than or equals condition based on a key @a key and a value @a v
*/
inline condition operator>=(const key &key, std::string_view v)
{
std::ostringstream s;
s << " >= " << 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)
{ return r[item_name].compare(v, icase) >= 0; },
s.str()));
}

/**
* @brief Operator to create a less than condition based on a key @a key and a value @a v
*/
inline condition operator<(const key &key, std::string_view v)
{
std::ostringstream s;
s << " < " << 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)
{ return r[item_name].compare(v, icase) < 0; },
s.str()));
}

/**
* @brief Operator to create a less than or equals condition based on a key @a key and a value @a v
*/
inline condition operator<=(const key &key, std::string_view v)
{
std::ostringstream s;
s << " <= " << 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)
{ return r[item_name].compare(v, icase) <= 0; },
s.str()));
}

Expand Down Expand Up @@ -1146,7 +1337,7 @@ namespace literals
* @param length The length of @a text
* @return key The cif::key created
*/
inline key operator""_key(const char *text, size_t length)
inline key operator""_key(const char *text, std::size_t length)
{
return key(std::string(text, length));
}
Expand Down
Loading

0 comments on commit 588e075

Please sign in to comment.