1 // Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #ifndef VK_DEBUG_VARIABLE_HPP_
16 #define VK_DEBUG_VARIABLE_HPP_
17
18 #include "ID.hpp"
19 #include "Type.hpp"
20 #include "Value.hpp"
21
22 #include <memory>
23 #include <mutex>
24 #include <string>
25 #include <unordered_map>
26 #include <vector>
27
28 namespace vk {
29 namespace dbg {
30
31 // Variable is a named value.
32 struct Variable
33 {
34 std::string name;
35 std::shared_ptr<Value> value;
36 };
37
38 // VariableContainer is a collection of named values.
39 class VariableContainer : public Value
40 {
41 public:
42 using ID = dbg::ID<VariableContainer>;
43
44 inline VariableContainer(ID id);
45
46 // foreach() calls cb with each of the variables in the container.
47 // F must be a function with the signature void(const Variable&).
48 template<typename F>
49 inline void foreach(size_t startIndex, size_t count, const F &cb) const;
50
51 // find() looks up the variable with the given name.
52 // If the variable with the given name is found, cb is called with the
53 // variable and find() returns true.
54 template<typename F>
55 inline bool find(const std::string &name, const F &cb) const;
56
57 // put() places the variable var into the container.
58 inline void put(const Variable &var);
59
60 // put() places the variable with the given name and value into the container.
61 inline void put(const std::string &name, const std::shared_ptr<Value> &value);
62
63 // extend() adds base to the list of VariableContainers that will be
64 // searched and traversed for variables.
65 inline void extend(const std::shared_ptr<VariableContainer> &base);
66
67 // The unique identifier of the variable.
68 const ID id;
69
70 private:
71 struct ForeachIndex
72 {
73 size_t start;
74 size_t count;
75 };
76
77 template<typename F>
78 inline void foreach(ForeachIndex &index, const F &cb) const;
79
80 inline std::shared_ptr<Type> type() const override;
81 inline const void *get() const override;
82
83 mutable std::mutex mutex;
84 std::vector<Variable> variables;
85 std::unordered_map<std::string, int> indices;
86 std::vector<std::shared_ptr<VariableContainer>> extends;
87 };
88
VariableContainer(ID id)89 VariableContainer::VariableContainer(ID id)
90 : id(id)
91 {}
92
93 template<typename F>
foreach(size_t startIndex,size_t count,const F & cb) const94 void VariableContainer::foreach(size_t startIndex, size_t count, const F &cb) const
95 {
96 auto index = ForeachIndex{ startIndex, count };
97 foreach(index, cb);
98 }
99
100 template<typename F>
foreach(ForeachIndex & index,const F & cb) const101 void VariableContainer::foreach(ForeachIndex &index, const F &cb) const
102 {
103 std::unique_lock<std::mutex> lock(mutex);
104 for(size_t i = index.start; i < variables.size() && i < index.count; i++)
105 {
106 cb(variables[i]);
107 }
108
109 index.start -= std::min(index.start, variables.size());
110 index.count -= std::min(index.count, variables.size());
111
112 for(auto &base : extends)
113 {
114 base->foreach(index, cb);
115 }
116 }
117
118 template<typename F>
find(const std::string & name,const F & cb) const119 bool VariableContainer::find(const std::string &name, const F &cb) const
120 {
121 std::unique_lock<std::mutex> lock(mutex);
122 for(auto const &var : variables)
123 {
124 if(var.name == name)
125 {
126 cb(var);
127 return true;
128 }
129 }
130 for(auto &base : extends)
131 {
132 if(base->find(name, cb))
133 {
134 return true;
135 }
136 }
137 return false;
138 }
139
put(const Variable & var)140 void VariableContainer::put(const Variable &var)
141 {
142 std::unique_lock<std::mutex> lock(mutex);
143 auto it = indices.find(var.name);
144 if(it == indices.end())
145 {
146 indices.emplace(var.name, variables.size());
147 variables.push_back(var);
148 }
149 else
150 {
151 variables[it->second].value = var.value;
152 }
153 }
154
put(const std::string & name,const std::shared_ptr<Value> & value)155 void VariableContainer::put(const std::string &name,
156 const std::shared_ptr<Value> &value)
157 {
158 put({ name, value });
159 }
160
extend(const std::shared_ptr<VariableContainer> & base)161 void VariableContainer::extend(const std::shared_ptr<VariableContainer> &base)
162 {
163 std::unique_lock<std::mutex> lock(mutex);
164 extends.emplace_back(base);
165 }
166
type() const167 std::shared_ptr<Type> VariableContainer::type() const
168 {
169 return TypeOf<VariableContainer>::get();
170 }
171
get() const172 const void *VariableContainer::get() const
173 {
174 return nullptr;
175 }
176
177 } // namespace dbg
178 } // namespace vk
179
180 #endif // VK_DEBUG_VARIABLE_HPP_