diff options
Diffstat (limited to 'build/rule-map')
-rw-r--r-- | build/rule-map | 70 |
1 files changed, 63 insertions, 7 deletions
diff --git a/build/rule-map b/build/rule-map index 883800b..0ef0036 100644 --- a/build/rule-map +++ b/build/rule-map @@ -8,8 +8,9 @@ #include <map> #include <vector> #include <string> +#include <memory> // unique_ptr #include <typeindex> -#include <functional> // reference_wrapper +#include <functional> // reference_wrapper #include <butl/prefix-map> @@ -25,21 +26,76 @@ namespace build butl::prefix_map<std::string, // Rule hint. std::reference_wrapper<rule>, '.'>>; - // This is an "indexed map" with (operation_id - 1) being the - // index. + // This is an "indexed map" with operation_id being the index. Entry + // with id 0 is a wildcard. // - class rule_map: public std::vector<target_type_rule_map> + class operation_rule_map { public: template <typename T> void insert (operation_id oid, const char* hint, rule& r) { - if (oid > size ()) - resize (oid < 3 ? 3 : oid); // 3 is the number of builtin operations. + // 3 is the number of builtin operations. + // + if (oid >= map_.size ()) + map_.resize ((oid < 3 ? 3 : oid) + 1); - (*this)[oid - 1][typeid (T)].emplace (hint, r); + map_[oid][typeid (T)].emplace (hint, r); } + + // Return NULL if not found. + // + const target_type_rule_map* + operator[] (operation_id oid) const + { + return map_.size () > oid ? &map_[oid] : nullptr; + } + + private: + std::vector<target_type_rule_map> map_; + }; + + // This is another indexed map but this time meta_operation_id is the + // index. The implementation is different, however: here we use a linked + // list with the first, statically-allocated node corresponding to the + // perform meta-operation. The idea is to try and get away with a dynamic + // allocation for the common cases since most rules will be registered + // for perform, at least on non-root scopes. + // + class rule_map + { + public: + template <typename T> + void + insert (meta_operation_id mid, operation_id oid, const char* hint, rule& r) + { + if (mid_ == mid) + map_.insert<T> (oid, hint, r); + else + { + if (next_ == nullptr) + next_.reset (new rule_map (mid)); + + next_->insert<T> (mid, oid, hint, r); + } + } + + // Return NULL if not found. + // + const operation_rule_map* + operator[] (meta_operation_id mid) const + { + return mid == mid_ ? &map_ : next_ == nullptr ? nullptr : (*next_)[mid]; + } + + explicit + rule_map (meta_operation_id mid = perform_id): mid_ (mid) {} + + private: + meta_operation_id mid_; + operation_rule_map map_; + std::unique_ptr<rule_map> next_; }; } |