aboutsummaryrefslogtreecommitdiff
path: root/build/rule-map
diff options
context:
space:
mode:
Diffstat (limited to 'build/rule-map')
-rw-r--r--build/rule-map70
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_;
};
}