// file : build/rule-map -*- C++ -*- // copyright : Copyright (c) 2014-2015 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file #ifndef BUILD_RULE_MAP #define BUILD_RULE_MAP #include <map> #include <vector> #include <string> #include <memory> // unique_ptr #include <typeindex> #include <functional> // reference_wrapper #include <butl/prefix-map> #include <build/types> #include <build/operation> namespace build { class rule; using target_type_rule_map = std::map< std::type_index, // Target type. butl::prefix_map<std::string, // Rule hint. std::reference_wrapper<rule>, '.'>>; // This is an "indexed map" with operation_id being the index. Entry // with id 0 is a wildcard. // class operation_rule_map { public: template <typename T> void insert (operation_id oid, const char* hint, rule& r) { // 3 is the number of builtin operations. // if (oid >= map_.size ()) map_.resize ((oid < 3 ? 3 : oid) + 1); 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; } bool empty () const {return map_.empty ();} 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) {} bool empty () const {return map_.empty () && next_ == nullptr;} private: meta_operation_id mid_; operation_rule_map map_; std::unique_ptr<rule_map> next_; }; } #endif // BUILD_RULE_MAP