From 9531673b2c627d94bea3e136ea956eca6a7364a3 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Tue, 9 Mar 2021 20:49:16 +0000 Subject: [PATCH] [Project] Css: Rework css block structure --- src/libserver/css/css_property.hxx | 2 + src/libserver/css/css_rule.cxx | 97 ++++++++++++++++++++++++++---- src/libserver/css/css_rule.hxx | 94 ++++++++++++++++++++++++----- src/libserver/css/css_value.hxx | 17 +++--- 4 files changed, 176 insertions(+), 34 deletions(-) diff --git a/src/libserver/css/css_property.hxx b/src/libserver/css/css_property.hxx index 597fc20c5..b72b655f9 100644 --- a/src/libserver/css/css_property.hxx +++ b/src/libserver/css/css_property.hxx @@ -118,6 +118,8 @@ struct alignas(int) css_property { constexpr auto is_normal_number(void) const -> bool { return type == css_property_type::PROPERTY_OPACITY; } + + auto operator==(const css_property &other) const { return type == other.type; } }; diff --git a/src/libserver/css/css_rule.cxx b/src/libserver/css/css_rule.cxx index a29577fe9..a706c759c 100644 --- a/src/libserver/css/css_rule.cxx +++ b/src/libserver/css/css_rule.cxx @@ -15,9 +15,87 @@ */ #include "css_rule.hxx" +#include namespace rspamd::css { +/* Class methods */ +void css_rule::override_values(const css_rule &other) +{ + values.resize(0); + values.reserve(other.values.size()); + + std::copy(other.values.begin(), other.values.end(), + std::back_inserter(values)); +} + +void css_rule::merge_values(const css_rule &other) +{ + int bits = 0; + /* Ensure that our bitset is large enough */ + static_assert(static_cast(css_value::css_value_type::CSS_VALUE_NYI) << 1 < + std::numeric_limits::max()); + + for (const auto &v : values) { + bits |= static_cast(v.type); + } + + /* Copy only not set values */ + std::copy_if(other.values.begin(), other.values.end(), std::back_inserter(values), + [&bits](const auto &elt) -> bool { + return !isset(&bits, static_cast(elt.type)); + }); +} + +auto css_declarations_block::add_rule(rule_shared_ptr &&rule) -> void +{ + auto it = rules.find(rule); + auto &&remote_prop = rule->get_prop(); + + if (it != rules.end()) { + auto &&local_rule = *it; + auto &&local_prop = local_rule->get_prop(); + + if (local_prop.flag == css_property_flag::FLAG_IMPORTANT) { + if (remote_prop.flag == css_property_flag::FLAG_IMPORTANT) { + local_rule->override_values(*rule); + } + else { + /* Ignore remote not important over local important */ + local_rule->merge_values(*rule); + } + } + else if (local_prop.flag == css_property_flag::FLAG_NOT_IMPORTANT) { + if (remote_prop.flag == css_property_flag::FLAG_NOT_IMPORTANT) { + local_rule->override_values(*rule); + } + else { + /* Ignore local not important over important */ + local_rule->merge_values(*rule); + } + } + else { + if (remote_prop.flag == css_property_flag::FLAG_IMPORTANT) { + /* Override with remote */ + local_rule->override_values(*rule); + } + else if (remote_prop.flag == css_property_flag::FLAG_NOT_IMPORTANT) { + /* Ignore remote not important over local normal */ + } + else { + /* Merge both */ + local_rule->merge_values(*rule); + } + } + } +} + +} + +namespace rspamd::css { + +/* Static functions */ + static auto allowed_property_value(const css_property &prop, const css_consumed_block &parser_block) -> std::optional @@ -70,15 +148,15 @@ allowed_property_value(const css_property &prop, const css_consumed_block &parse auto process_declaration_tokens(rspamd_mempool_t *pool, const blocks_gen_functor &next_block_functor) - -> declarations_vec + -> css_declarations_block { - declarations_vec ret; + css_declarations_block ret; bool can_continue = true; css_property cur_property{css_property_type::PROPERTY_NYI, css_property_flag::FLAG_NORMAL}; static const css_property bad_property{css_property_type::PROPERTY_NYI, css_property_flag::FLAG_NORMAL}; - std::unique_ptr cur_rule; + std::shared_ptr cur_rule; enum { parse_property, @@ -121,7 +199,7 @@ auto process_declaration_tokens(rspamd_mempool_t *pool, } else { state = parse_value; - cur_rule = std::make_unique(cur_property); + cur_rule = std::make_shared(cur_property); } } } @@ -131,7 +209,7 @@ auto process_declaration_tokens(rspamd_mempool_t *pool, const auto &parser_tok = next_tok.get_token_or_empty(); if (parser_tok.type == css_parser_token::token_type::semicolon_token) { - ret.push_back(std::move(cur_rule)); + ret.add_rule(std::move(cur_rule)); state = parse_property; seen_not = false; continue; @@ -199,7 +277,7 @@ auto process_declaration_tokens(rspamd_mempool_t *pool, break; case css_consumed_block::parser_tag_type::css_eof_block: if (state == parse_value) { - ret.push_back(std::move(cur_rule)); + ret.add_rule(std::move(cur_rule)); } can_continue = false; break; @@ -212,14 +290,9 @@ auto process_declaration_tokens(rspamd_mempool_t *pool, return ret; /* copy elision */ } -void css_rule::add_value(std::unique_ptr &&value) -{ - values.emplace_back(std::forward>(value)); -} - void css_rule::add_value(const css_value &value) { - values.emplace_back(std::make_unique(css_value{value})); + values.push_back(value); } } \ No newline at end of file diff --git a/src/libserver/css/css_rule.hxx b/src/libserver/css/css_rule.hxx index 41a6ef3be..dd6158538 100644 --- a/src/libserver/css/css_rule.hxx +++ b/src/libserver/css/css_rule.hxx @@ -21,6 +21,7 @@ #include "css_value.hxx" #include "css_property.hxx" #include "css_parser.hxx" +#include "contrib/robin-hood/robin_hood.h" #include #include @@ -28,29 +29,35 @@ namespace rspamd::css { class css_rule { css_property prop; - using css_values_vec = std::vector >; + using css_values_vec = std::vector; css_values_vec values; + public: /* We must create css rule explicitly from a property and values */ css_rule() = delete; + css_rule(const css_rule &other) = delete; + /* Constructors */ - css_rule(css_rule &&other) = default; - explicit css_rule(css_property &&prop, css_values_vec &&values) : - prop(prop), values(std::forward(values)) {} - explicit css_rule(const css_property &prop) : prop(prop), values{} {} + css_rule(css_rule &&other) noexcept = default; + + explicit css_rule(css_property &&prop, css_values_vec &&values) noexcept : + prop(prop), values(std::forward(values)) {} + + explicit css_rule(const css_property &prop) noexcept : prop(prop), values{} {} + /* Methods */ - void add_value(std::unique_ptr &&value); - void add_value(const css_value &value); - constexpr const css_values_vec& get_values(void) const { return values; } - constexpr const css_property& get_prop(void) const { return prop; } -}; + /* Comparison is special, as we care merely about property, not the values */ + auto operator==(const css_rule &other) const { return prop == other.prop; } -using declarations_vec = std::vector>; + constexpr const css_values_vec &get_values(void) const { return values; } + constexpr const css_property &get_prop(void) const { return prop; } -auto process_declaration_tokens(rspamd_mempool_t *pool, - const blocks_gen_functor &next_token_functor) - -> declarations_vec; + /* Import values from another rules according to the importance */ + void override_values(const css_rule &other); + void merge_values(const css_rule &other); + void add_value(const css_value &value); +}; } @@ -59,10 +66,67 @@ namespace std { template<> class hash { public: - constexpr size_t operator() (const rspamd::css::css_rule &rule) const { + constexpr auto operator()(const rspamd::css::css_rule &rule) const -> auto { return hash()(rule.get_prop()); } }; + +} + +namespace rspamd::css { + +/* + * We have to define transparent hash and compare methods + * + * TODO: move to some utility library + */ +template +struct shared_ptr_equal { + using is_transparent = void; /* We want to find values in a set of shared_ptr by reference */ + auto operator()(const std::shared_ptr &a, const std::shared_ptr &b) const { + return (*a) == (*b); + } + auto operator()(const std::shared_ptr &a, const T &b) const { + return (*a) == b; + } + auto operator()(const T &a, const std::shared_ptr &b) const { + return a == (*b); + } +}; + +template +struct shared_ptr_hash { + using is_transparent = void; /* We want to find values in a set of shared_ptr by reference */ + auto operator()(const std::shared_ptr &a) const { + return std::hash()(*a); + } + auto operator()(const T &a) const { + return std::hash()(a); + } +}; + +class css_declarations_block { +public: + using rule_shared_ptr = std::shared_ptr; + using rule_shared_hash = shared_ptr_hash; + using rule_shared_eq = shared_ptr_equal; + css_declarations_block() = default; + auto add_rule(rule_shared_ptr &&rule) -> void; + auto get_rules(void) const -> const auto & { + return rules; + } + + auto has_rule(const css_rule &rule) const -> bool { + return (rules.find(rule) != rules.end()); + } +private: + robin_hood::unordered_flat_set rules; +}; + +auto process_declaration_tokens(rspamd_mempool_t *pool, + const blocks_gen_functor &next_token_functor) + -> css_declarations_block; + } #endif //RSPAMD_CSS_RULE_HXX \ No newline at end of file diff --git a/src/libserver/css/css_value.hxx b/src/libserver/css/css_value.hxx index 64109c5f0..d7c8f5c45 100644 --- a/src/libserver/css/css_value.hxx +++ b/src/libserver/css/css_value.hxx @@ -59,20 +59,23 @@ enum class css_display_value { * for simplicity */ struct css_value { + /* Bitset of known types */ enum class css_value_type { - CSS_VALUE_COLOR, - CSS_VALUE_NUMBER, - CSS_VALUE_DISPLAY, - CSS_VALUE_DIMENSION, - CSS_VALUE_NYI, - } type; - + CSS_VALUE_COLOR = 1 << 0, + CSS_VALUE_NUMBER = 1 << 1, + CSS_VALUE_DISPLAY = 1 << 2, + CSS_VALUE_DIMENSION = 1 << 3, + CSS_VALUE_NYI = 1 << 4, + }; + + css_value_type type; std::variant value; + css_value() : type(css_value_type::CSS_VALUE_NYI) {} css_value(const css_color &color) : type(css_value_type::CSS_VALUE_COLOR), value(color) {} css_value(double num) : -- 2.39.5