File content_filtered_topic.hpp
File List > astutedds > dcps > content_filtered_topic.hpp
Go to the documentation of this file
#ifndef ASTUTEDDS_DCPS_CONTENT_FILTERED_TOPIC_HPP
#define ASTUTEDDS_DCPS_CONTENT_FILTERED_TOPIC_HPP
#include <astutedds/dcps/qos.hpp>
#include <astutedds/dcps/topic_description.hpp>
#include <string>
#include <vector>
#include <memory>
#include <functional>
#include <variant>
#include <regex>
#include <stdexcept>
namespace astutedds::dcps
{
// Forward declarations
class Topic;
class DomainParticipant;
using FilterValue = std::variant<int64_t, double, std::string, bool>;
enum class FilterOperator
{
EQUAL, // =
NOT_EQUAL, // != or <>
LESS_THAN, // <
LESS_EQUAL, // <=
GREATER_THAN, // >
GREATER_EQUAL, // >=
LIKE, // LIKE (pattern matching)
BETWEEN, // BETWEEN ... AND ...
IN, // IN (value list)
IS_NULL, // IS NULL
IS_NOT_NULL // IS NOT NULL
};
enum class LogicalOperator
{
AND,
OR,
NOT
};
struct FilterCondition
{
std::string field_name;
FilterOperator op;
std::vector<FilterValue> values;
bool negated{false};
};
struct FilterExpression;
struct FilterExpressionNode
{
std::variant<
FilterCondition,
std::pair<LogicalOperator, std::vector<std::unique_ptr<FilterExpressionNode>>>>
content;
};
class FilterExpression
{
public:
FilterExpression() = default;
explicit FilterExpression(const std::string &expression,
const std::vector<std::string> ¶meter_names = {});
template <typename SampleType>
bool evaluate(const SampleType &sample,
std::function<FilterValue(const SampleType &, const std::string &)> get_field) const;
const std::string &expression_string() const { return expression_; }
const std::vector<std::string> ¶meters() const { return parameters_; }
void set_parameter(size_t index, const std::string &value);
bool is_valid() const { return valid_; }
const std::string &error_message() const { return error_; }
private:
bool parse();
bool parse_or_expression(size_t &pos);
bool parse_and_expression(size_t &pos);
bool parse_condition(size_t &pos);
void skip_whitespace(size_t &pos);
std::string parse_identifier(size_t &pos);
FilterValue parse_value(size_t &pos);
FilterOperator parse_operator(size_t &pos);
bool evaluate_condition(const FilterCondition &cond,
const std::function<FilterValue(const std::string &)> &get_field) const;
bool evaluate_node(const FilterExpressionNode &node,
const std::function<FilterValue(const std::string &)> &get_field) const;
static bool compare_values(const FilterValue &lhs, FilterOperator op, const FilterValue &rhs);
private:
std::string expression_;
std::vector<std::string> parameters_;
std::unique_ptr<FilterExpressionNode> root_;
bool valid_{false};
std::string error_;
};
class ContentFilteredTopic : public TopicDescription
{
public:
ContentFilteredTopic(const std::string &name,
std::shared_ptr<Topic> related_topic,
const std::string &filter_expression,
const std::vector<std::string> &expression_parameters = {});
ContentFilteredTopic(const std::string &name,
Topic *related_topic,
const std::string &filter_expression,
const std::vector<std::string> &expression_parameters = {});
// TopicDescription interface (const char* for PSM)
const char *get_name() const override { return name_.c_str(); }
const char *get_type_name() const override;
const std::string &name() const { return name_; }
const std::string &type_name() const;
Topic *get_related_topic() const { return related_topic_raw_; }
const std::string &get_filter_expression() const { return filter_expression_; }
const std::vector<std::string> &get_expression_parameters() const
{
return expression_parameters_;
}
int set_expression_parameters(const std::vector<std::string> ¶meters);
template <typename SampleType>
bool evaluate(const SampleType &sample,
std::function<FilterValue(const SampleType &, const std::string &)> get_field) const
{
return filter_.evaluate(sample, get_field);
}
bool is_filter_valid() const { return filter_.is_valid(); }
const std::string &get_filter_error() const { return filter_.error_message(); }
private:
std::string name_;
std::shared_ptr<Topic> related_topic_;
Topic *related_topic_raw_{nullptr}; // non-null when constructed from raw ptr
std::string filter_expression_;
std::vector<std::string> expression_parameters_;
FilterExpression filter_;
};
std::unique_ptr<ContentFilteredTopic> create_content_filtered_topic(
DomainParticipant &participant,
const std::string &name,
std::shared_ptr<Topic> related_topic,
const std::string &filter_expression,
const std::vector<std::string> &expression_parameters = {});
// ============================================================================
// Template Implementation
// ============================================================================
template <typename SampleType>
bool FilterExpression::evaluate(const SampleType &sample,
std::function<FilterValue(const SampleType &, const std::string &)> get_field) const
{
if (!valid_ || !root_)
{
return true; // No filter or invalid filter passes all
}
auto field_getter = [&sample, &get_field](const std::string &field) -> FilterValue
{
return get_field(sample, field);
};
return evaluate_node(*root_, field_getter);
}
} // namespace astutedds::dcps
#endif // ASTUTEDDS_DCPS_CONTENT_FILTERED_TOPIC_HPP