aboutsummaryrefslogtreecommitdiff
path: root/build2/target-key
blob: ef59d63aae1010860db990c9c6070f2a4eb89a8c (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
// file      : build2/target-key -*- C++ -*-
// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
// license   : MIT; see accompanying LICENSE file

#ifndef BUILD2_TARGET_KEY
#define BUILD2_TARGET_KEY

#include <map>
#include <functional> // hash

#include <butl/utility> // compare_c_string

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

#include <build2/target-type>

namespace build2
{
  // Light-weight (by being shallow-pointing) target key.
  //
  class 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;
    const string* const& ext;

    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);}

    // The above references have to track the original objects so we cannot
    // have assignment.
    //
    // @@ We could use references for all members, not just ext.
    //
    target_key (target_key&&) = default;
    target_key (const target_key&) = default;

    target_key& operator= (target_key&&) = delete;
    target_key& operator= (const target_key&) = delete;
  };

  inline bool
  operator== (const target_key& x, const target_key& y)
  {
    // Unspecified and specified extension are assumed equal. The extension
    // strings are from the pool, so we can just compare pointers.
    //
    return
      x.type == y.type &&
      *x.dir == *y.dir &&
      *x.out == *y.out &&
      *x.name == *y.name &&
      (x.ext == nullptr || y.ext == nullptr || x.ext == y.ext);
  }

  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() with the current stream verbosity as a third argument.
  // Both are defined in target.cxx.
  //
  ostream&
  operator<< (ostream&, const target_key&);

  ostream&
  to_stream (ostream&, const target_key&, uint16_t ext_verb);
}

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 // BUILD2_TARGET_KEY