C++ Device API Reference Manual
Reference documentation for the Simics C++ Device API.
 
Loading...
Searching...
No Matches
hierarchical-object-name.h
Go to the documentation of this file.
1// -*- mode: C++; c-file-style: "virtutech-c++" -*-
2
3/*
4 © 2023 Intel Corporation
5
6 This software and the related documents are Intel copyrighted materials, and
7 your use of them is governed by the express license under which they were
8 provided to you ("License"). Unless the License provides otherwise, you may
9 not use, modify, copy, publish, distribute, disclose or transmit this software
10 or the related documents without Intel's prior written permission.
11
12 This software and the related documents are provided as is, with no express or
13 implied warranties, other than those that are expressly stated in the License.
14*/
15
16#ifndef SIMICS_TYPE_HIERARCHICAL_OBJECT_NAME_H
17#define SIMICS_TYPE_HIERARCHICAL_OBJECT_NAME_H
18
19#include <string_view>
20#include <string>
21#ifdef __GNUC__
22#include <cctype> // isalpha
23#endif
24#include <utility> // pair
25#include <stdexcept>
26#include <vector>
27#include <map>
28
29namespace simics {
30namespace detail {
31
32/*
33 * Literal type that extends string_view type
34 * Optimized to save the compile time on the large register data
35 * Build with DEBUG enables the name validation
36 */
37class HierarchicalObjectName : public std::string_view {
38 public:
39 constexpr HierarchicalObjectName() noexcept
40 : std::string_view() {}
42 const HierarchicalObjectName& other) noexcept = default;
43 constexpr HierarchicalObjectName(const char* s, std::size_t count)
44 : std::string_view(s, count) {
45#ifndef NDEBUG
46 validate_name();
47#endif
48 }
49 constexpr HierarchicalObjectName(const char* s) // NOLINT(runtime/explicit)
50 : std::string_view(s) {
51#ifndef NDEBUG
52 validate_name();
53#endif
54 }
55
56 // The base name without array information
57 constexpr std::string_view base_name() const {
58 return substr(0, find('['));
59 }
60
61 // The array information without base name
62 constexpr std::string_view array_str() const {
63 auto pos = find('[');
64 if (pos != npos) {
65 return substr(pos);
66 }
67 return {};
68 }
69
70 // @param width the distance between successive elements in the innermost
71 // array dimension if no stride information provided
72 // @return a map from the name to its memory offset (from the first item)
73 // in an array by alphabetic order
74 std::map<std::string, size_t> arrayNamesToOffsets(size_t width) const {
75 if (width == 0) {
76 throw std::invalid_argument("Invalid width 0");
77 }
78
79 if (array_str().empty()) {
80 return {};
81 }
82
83 auto sizes_and_strides = arraySizesAndStrides();
84 // Update strides for all dimensions
85 for (auto it = sizes_and_strides.rbegin();
86 it != sizes_and_strides.rend(); ++it) {
87 if (it->second != 0) {
88 continue;
89 }
90 if (it == sizes_and_strides.rbegin()) {
91 // The innermost dimension, use width as the stride
92 it->second = width;
93 } else {
94 // Use the sum of distances of inner dimension elements
95 it->second = (it - 1)->first * (it - 1)->second;
96 }
97 }
98
99 std::map<std::string, size_t> names_to_offsets;
100 std::vector<size_t> indices(sizes_and_strides.size(), 0);
101 generateNamesToOffsets(sizes_and_strides, 0, &indices,
102 &names_to_offsets);
103 return names_to_offsets;
104 }
105
106 // @return the size and stride of all array dimensions
107 // Returned value should be buffered for better performance
108 std::vector<std::pair<size_t, size_t>> arraySizesAndStrides() const {
109 auto s = array_str();
110 if (s.empty()) {
111 return {};
112 }
113
114 std::size_t content_pos = npos;
115 std::vector<std::pair<size_t, size_t>> dims_;
116 for (size_t i = 0; i < s.size(); ++i) {
117 auto c = s[i];
118 if (c == '[') {
119 if (content_pos != npos) {
120 throw std::logic_error("Name has unbalanced brackets");
121 }
122 content_pos = i + 1;
123 } else if (c == ']') {
124 if (content_pos == npos) {
125 throw std::logic_error("Name has unbalanced brackets");
126 }
127 if (content_pos == i) {
128 throw std::logic_error("Name has nothing in brackets");
129 }
130 const auto &[size, stride] = sizeAndStride(
131 s.substr(content_pos, i - content_pos));
132 if (size == 0) {
133 throw std::logic_error("Dimension size is 0");
134 }
135 dims_.push_back({size, stride});
136 content_pos = npos;
137 }
138 }
139
140 if (content_pos != npos) {
141 throw std::logic_error("Name has unbalanced brackets");
142 }
143
144 return dims_;
145 }
146
147 private:
148#ifndef __GNUC__
149 // Microsoft Visual Studio 2022 treat these functions as non-constexpr and
150 // generates C3615 error
151 static constexpr bool isalpha(char c) {
152 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
153 }
154
155 static constexpr bool isalnum(char c) {
156 return isalpha(c) || (c >= '0' && c <= '9');
157 }
158#endif
159
160 // Validation the name (array part is checked when information is requested)
161 constexpr void validate_name() const {
162#ifdef __GNUC__
163 using std::isalpha;
164 using std::isalnum;
165#endif
166 if (empty()) {
167 throw std::invalid_argument("Empty name is not allowed");
168 }
169 if (!isalpha(front())) {
170 throw std::invalid_argument(
171 std::string("Name (") + data() \
172 + ") does not begin with an alphabetic character");
173 }
174
175 // Validate base_name
176 for (const auto &c : base_name()) {
177 if (c != '_' && !isalnum(c)) {
178 throw std::invalid_argument(
179 std::string("Character (") + c \
180 + ") is not allowed to use in a name");
181 }
182 }
183 }
184
185 std::pair<size_t, size_t> sizeAndStride(std::string_view s) const {
186 auto stride_pos = s.find(" stride ");
187 size_t size;
188 size_t stride = 0;
189
190 try {
191 if (stride_pos != npos) {
192 size = std::stoi(s.substr(0, stride_pos).data());
193 stride = std::stoi(s.substr(stride_pos + 8).data());
194 } else {
195 if (s.find_first_not_of("0123456789") != npos) {
196 throw std::invalid_argument("non-digit character");
197 }
198 size = std::stoi(s.data());
199 }
200 } catch (const std::exception &e) {
201 throw std::invalid_argument(
202 std::string("Array contents are malformed: ") + e.what());
203 }
204
205 return {size, stride};
206 }
207
208 void generateNamesToOffsets(const std::vector<std::pair<size_t, size_t>>
209 &dims_info,
210 size_t current_dim,
211 std::vector<size_t> *indices,
212 std::map<std::string, size_t>
213 *names_to_offsets) const {
214 if (current_dim == dims_info.size()) {
215 // We have reached the innermost dimension, so generate the name and
216 // offset and add it to the vector
217 std::string name {base_name()};
218 size_t offset = 0;
219 for (size_t i = 0; i < indices->size(); i++) {
220 name += "[" + std::to_string((*indices)[i]) + "]";
221 offset += (*indices)[i] * dims_info[i].second;
222 }
223 (*names_to_offsets)[name] = offset;
224 } else {
225 // Iterate over each index of the current dimension and recurse
226 for (size_t i = 0; i < dims_info[current_dim].first; i++) {
227 (*indices)[current_dim] = i;
228 generateNamesToOffsets(dims_info, current_dim + 1,
229 indices, names_to_offsets);
230 }
231 }
232 }
233};
234
235} // namespace detail
236} // namespace simics
237
238#endif
Definition: hierarchical-object-name.h:37
std::map< std::string, size_t > arrayNamesToOffsets(size_t width) const
Definition: hierarchical-object-name.h:74
constexpr HierarchicalObjectName(const char *s, std::size_t count)
Definition: hierarchical-object-name.h:43
std::vector< std::pair< size_t, size_t > > arraySizesAndStrides() const
Definition: hierarchical-object-name.h:108
constexpr std::string_view array_str() const
Definition: hierarchical-object-name.h:62
constexpr HierarchicalObjectName(const HierarchicalObjectName &other) noexcept=default
constexpr HierarchicalObjectName() noexcept
Definition: hierarchical-object-name.h:39
constexpr HierarchicalObjectName(const char *s)
Definition: hierarchical-object-name.h:49
constexpr std::string_view base_name() const
Definition: hierarchical-object-name.h:57
Definition: attr-value.h:23
Definition: common-types.h:63