/src/CMake/Source/cmVariableWatch.cxx
Line | Count | Source |
1 | | /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
2 | | file LICENSE.rst or https://cmake.org/licensing for details. */ |
3 | | #include "cmVariableWatch.h" |
4 | | |
5 | | #include <array> |
6 | | #include <memory> |
7 | | #include <utility> |
8 | | #include <vector> |
9 | | |
10 | | std::string const& cmVariableWatch::GetAccessAsString(int access_type) |
11 | 0 | { |
12 | 0 | static std::array<std::string, 6> const cmVariableWatchAccessStrings = { |
13 | 0 | { "READ_ACCESS", "UNKNOWN_READ_ACCESS", "UNKNOWN_DEFINED_ACCESS", |
14 | 0 | "MODIFIED_ACCESS", "REMOVED_ACCESS", "NO_ACCESS" } |
15 | 0 | }; |
16 | 0 | if (access_type < 0 || access_type >= cmVariableWatch::NO_ACCESS) { |
17 | 0 | access_type = cmVariableWatch::NO_ACCESS; |
18 | 0 | } |
19 | 0 | return cmVariableWatchAccessStrings[access_type]; |
20 | 0 | } |
21 | | |
22 | 35 | cmVariableWatch::cmVariableWatch() = default; |
23 | | |
24 | 35 | cmVariableWatch::~cmVariableWatch() = default; |
25 | | |
26 | | bool cmVariableWatch::AddWatch(std::string const& variable, WatchMethod method, |
27 | | void* client_data /*=0*/, |
28 | | DeleteData delete_data /*=0*/) |
29 | 0 | { |
30 | 0 | auto p = std::make_shared<cmVariableWatch::Pair>(); |
31 | 0 | p->Method = method; |
32 | 0 | p->ClientData = client_data; |
33 | 0 | p->DeleteDataCall = delete_data; |
34 | 0 | cmVariableWatch::VectorOfPairs& vp = this->WatchMap[variable]; |
35 | 0 | for (auto& pair : vp) { |
36 | 0 | if (pair->Method == method && client_data && |
37 | 0 | client_data == pair->ClientData) { |
38 | | // Callback already exists |
39 | 0 | return false; |
40 | 0 | } |
41 | 0 | } |
42 | 0 | vp.push_back(std::move(p)); |
43 | 0 | return true; |
44 | 0 | } |
45 | | |
46 | | void cmVariableWatch::RemoveWatch(std::string const& variable, |
47 | | WatchMethod method, void* client_data /*=0*/) |
48 | 3 | { |
49 | 3 | if (!this->WatchMap.count(variable)) { |
50 | 3 | return; |
51 | 3 | } |
52 | 0 | cmVariableWatch::VectorOfPairs* vp = &this->WatchMap[variable]; |
53 | 0 | cmVariableWatch::VectorOfPairs::iterator it; |
54 | 0 | for (it = vp->begin(); it != vp->end(); ++it) { |
55 | 0 | if ((*it)->Method == method && |
56 | | // If client_data is NULL, we want to disconnect all watches against |
57 | | // the given method; otherwise match ClientData as well. |
58 | 0 | (!client_data || (client_data == (*it)->ClientData))) { |
59 | 0 | vp->erase(it); |
60 | 0 | return; |
61 | 0 | } |
62 | 0 | } |
63 | 0 | } |
64 | | |
65 | | bool cmVariableWatch::VariableAccessed(std::string const& variable, |
66 | | int access_type, char const* newValue, |
67 | | cmMakefile const* mf) const |
68 | 12 | { |
69 | 12 | auto mit = this->WatchMap.find(variable); |
70 | 12 | if (mit != this->WatchMap.end()) { |
71 | | // The strategy here is to copy the list of callbacks, and ignore |
72 | | // new callbacks that existing ones may add. |
73 | 0 | std::vector<std::weak_ptr<Pair>> vp(mit->second.begin(), |
74 | 0 | mit->second.end()); |
75 | 0 | for (auto& weak_it : vp) { |
76 | | // In the case where a callback was removed, the weak_ptr will not be |
77 | | // lockable, and so this ensures we don't attempt to call into freed |
78 | | // memory |
79 | 0 | if (auto it = weak_it.lock()) { |
80 | 0 | it->Method(variable, access_type, it->ClientData, newValue, mf); |
81 | 0 | } |
82 | 0 | } |
83 | 0 | return true; |
84 | 0 | } |
85 | 12 | return false; |
86 | 12 | } |