// file : build2/prerequisite -*- C++ -*- // copyright : Copyright (c) 2014-2016 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file #ifndef BUILD2_PREREQUISITE #define BUILD2_PREREQUISITE #include // hash #include #include #include #include #include namespace build2 { class scope; class target; // Light-weight (by being shallow-pointing) prerequisite key, similar // to (and based on) target key. // class prerequisite_key { public: typedef build2::scope scope_type; mutable const string* proj; // Can be NULL, from project_name_pool. target_key tk; // .dir and .out can be relative. mutable scope_type* scope; // Can be NULL if tk.dir is absolute. template bool is_a () const {return tk.is_a ();} bool is_a (const target_type& tt) const {return tk.is_a (tt);} }; inline bool operator== (const prerequisite_key& x, const prerequisite_key& y) { assert (x.scope == y.scope); // Can compare project name pointers since they are from project_name_pool. // return x.proj == y.proj && x.tk == y.tk; } inline bool operator!= (const prerequisite_key& x, const prerequisite_key& y) { return !(x == y); } ostream& operator<< (ostream&, const prerequisite_key&); } namespace std { // Note that we ignore the extension when calculating the hash because of // its special "unspecified" logic (see target_key::operator==). // template <> struct hash { using argument_type = build2::prerequisite_key; using result_type = size_t; size_t operator() (const build2::prerequisite_key& k) const noexcept { // Can hash project name pointers since they are from project_name_pool. // return build2::combine_hash (hash () (k.proj), hash () (k.tk)); } }; } namespace build2 { class prerequisite { public: typedef build2::target target_type; typedef build2::target_type target_type_type; typedef build2::scope scope_type; // Note that unlike targets, for prerequisites an empty out directory // means undetermined rather than being definitely in the out tree. // const string* const proj; // NULL if not project-qualified. const target_type_type& type; const dir_path dir; // Normalized absolute or relative (to scope). const dir_path out; // Empty, normalized absolute, or relative. const string name; const string* ext; // NULL if unspecified. scope_type& scope; target_type* target; // NULL if not yet resolved. Note that this should // always be the "primary target", not a member of // a target group. public: prerequisite (const string* p, const target_type_type& t, dir_path d, dir_path o, string n, const string* e, scope_type& s) : proj (p), type (t), dir (move (d)), out (move (o)), name (move (n)), ext (e), scope (s), target (nullptr) {} // Note that the returned key "tracks" the prerequisite; that is, any // updates to the prerequisite's members will be reflected in the key. // prerequisite_key key () const { return prerequisite_key {proj, {&type, &dir, &out, &name, ext}, &scope}; } public: // Prerequisite (target) type. // template bool is_a () const {return type.is_a ();} bool is_a (const target_type_type& tt) const {return type.is_a (tt);} }; inline bool operator== (const prerequisite& x, const prerequisite& y) { return x.key () == y.key (); } inline bool operator!= (const prerequisite& x, const prerequisite& y) { return !(x == y); } inline ostream& operator<< (ostream& os, const prerequisite& p) { return os << p.key (); } } namespace std { template <> struct hash { using argument_type = build2::prerequisite; using result_type = size_t; size_t operator() (const build2::prerequisite& p) const noexcept { return hash () (p.key ()); } }; } namespace build2 { // Set of prerequisites in a scope. // // Similar to targets, specified and unspecified extensions are considered // equal and we may update the extension in the existing entry. To make // this work we use a hash set. // struct prerequisite_set: std::unordered_set { pair insert (const string* proj, const target_type&, dir_path dir, dir_path out, string name, const string* ext, scope&, tracer&); pair insert (const string* proj, const target_key& tk, scope& s, tracer& t) { return insert (proj, *tk.type, *tk.dir, *tk.out, *tk.name, tk.ext, s, t); } }; } #endif // BUILD2_PREREQUISITE