aboutsummaryrefslogtreecommitdiff
path: root/build2/prerequisite
blob: 156a096224e5f98233d529ca01ac16fc10b0ebcc (plain)
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
// 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 <functional> // hash
#include <unordered_set>

#include <build2/types>
#include <build2/utility>

#include <build2/target-key>
#include <build2/diagnostics>

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 <typename T>
    bool is_a () const {return tk.is_a<T> ();}
    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<build2::prerequisite_key>
  {
    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<const string*> () (k.proj),
                                   hash<build2::target_key> () (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 <typename T>
    bool
    is_a () const {return type.is_a<T> ();}

    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<build2::prerequisite>
  {
    using argument_type = build2::prerequisite;
    using result_type = size_t;

    size_t
    operator() (const build2::prerequisite& p) const noexcept
    {
      return hash<build2::prerequisite_key> () (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<prerequisite>
  {
    pair<prerequisite&, bool>
    insert (const string* proj,
            const target_type&,
            dir_path dir,
            dir_path out,
            string name,
            const string* ext,
            scope&,
            tracer&);

    pair<prerequisite&, bool>
    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