// file : libbuild2/target-key.hxx -*- C++ -*- // license : MIT; see accompanying LICENSE file #ifndef LIBBUILD2_TARGET_KEY_HXX #define LIBBUILD2_TARGET_KEY_HXX #include <cstring> // strcmp() #include <libbuild2/types.hxx> #include <libbuild2/forward.hxx> #include <libbuild2/utility.hxx> #include <libbuild2/target-type.hxx> #include <libbuild2/export.hxx> namespace build2 { // Light-weight (by being shallow-pointing) target key. // class LIBBUILD2_SYMEXPORT target_key { public: const target_type* type; const dir_path* dir; // Can be relative if part of prerequisite_key. const dir_path* out; // Can be relative if part of prerequisite_key. const string* name; mutable optional<string> ext; // Absent - unspecified, empty - none. template <typename T> bool is_a () const {return type->is_a<T> ();} bool is_a (const target_type& tt) const {return type->is_a (tt);} // Append/return the target name or a pair of names if out-qualified. // void as_name (names&) const; names as_name () const { names r; as_name (r); return r; } }; inline bool operator== (const target_key& x, const target_key& y) { if (x.type != y.type || *x.dir != *y.dir || *x.out != *y.out || *x.name != *y.name) return false; // Unless fixed, unspecified and specified extensions are assumed equal. // const target_type& tt (*x.type); if (tt.fixed_extension == nullptr) return !x.ext || !y.ext || *x.ext == *y.ext; else { // Note that for performance reasons here we use the specified extension // without calling fixed_extension() to verify it matches. // const char* xe (x.ext ? x.ext->c_str () : tt.fixed_extension (x, nullptr /* root scope */)); const char* ye (y.ext ? y.ext->c_str () : tt.fixed_extension (y, nullptr /* root scope */)); return strcmp (xe, ye) == 0; } } inline bool operator!= (const target_key& x, const target_key& y) {return !(x == y);} // If the target type has a custom print function, call that. Otherwise, // call to_stream(). Both are defined in target.cxx. // LIBBUILD2_SYMEXPORT ostream& operator<< (ostream&, const target_key&); LIBBUILD2_SYMEXPORT ostream& to_stream (ostream&, const target_key&, optional<stream_verbosity> = nullopt); } namespace std { // Note that we ignore the extension when calculating the hash because of // its special "unspecified" logic (see operator== above). // template <> struct hash<build2::target_key> { using argument_type = build2::target_key; using result_type = size_t; size_t operator() (const build2::target_key& k) const noexcept { return build2::combine_hash ( hash<const build2::target_type*> () (k.type), hash<build2::dir_path> () (*k.dir), hash<build2::dir_path> () (*k.out), hash<string> () (*k.name)); } }; } #endif // LIBBUILD2_TARGET_KEY_HXX