1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
// 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* const type;
const dir_path* const dir; // Can be relative if part of prerequisite_key.
const dir_path* const out; // Can be relative if part of prerequisite_key.
const string* const 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
|