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#ifdef __GNUC__
20#include <cctype> // isalpha
21#endif
22#include <cstddef>
23#include <map>
24#include <stdexcept>
25#include <string>
26#include <string_view>
27#include <utility> // pair
28#include <vector>
29
30namespace simics {
31namespace detail {
32
44class HierarchicalObjectName : public std::string_view {
45 public:
46 constexpr HierarchicalObjectName() noexcept
47 : std::string_view() {}
49 const HierarchicalObjectName& other) noexcept = default;
50 constexpr HierarchicalObjectName(const_pointer s, size_type count)
51 : std::string_view(s, count) {
52 validate_name(*this);
53 }
55 const_pointer s) // NOLINT(runtime/explicit)
56 : std::string_view(s) {
57 validate_name(*this);
58 }
59
74 static constexpr void validate_name(std::string_view name) {
75#ifdef __GNUC__
76 using std::isalpha;
77 using std::isalnum;
78#endif
79 if (name.empty()) {
80 throw std::invalid_argument("Empty name is not allowed");
81 }
82 if (!isalpha(name.front())) {
83 throw std::invalid_argument(
84 std::string("Name (") + name.data() \
85 + ") does not begin with an alphabetic character");
86 }
87
88 // Validate base_name
89 for (const auto &c : name.substr(0, name.find('['))) {
90 if (c != '_' && !isalnum(c)) {
91 throw std::invalid_argument(
92 std::string("Character (") + c \
93 + ") is not allowed to use in a name");
94 }
95 }
96 }
97
99 constexpr std::string_view base_name() const {
100 return substr(0, find('['));
101 }
102
104 constexpr std::string_view array_str() const {
105 auto pos = find('[');
106 if (pos != npos) {
107 return substr(pos);
108 }
109 return {};
110 }
111
126 std::map<std::string, size_t> arrayNamesToOffsets(size_t width) const {
127 if (width == 0) {
128 throw std::invalid_argument("Invalid width 0");
129 }
130
131 if (array_str().empty()) {
132 return {};
133 }
134
135 auto sizes_and_strides = arraySizesAndStrides();
136 // Update strides for all dimensions
137 for (auto it = sizes_and_strides.rbegin();
138 it != sizes_and_strides.rend(); ++it) {
139 if (it->second != 0) {
140 continue;
141 }
142 if (it == sizes_and_strides.rbegin()) {
143 // The innermost dimension, use width as the stride
144 it->second = width;
145 } else {
146 // Use the sum of distances of inner dimension elements
147 it->second = (it - 1)->first * (it - 1)->second;
148 }
149 }
150
151 std::map<std::string, size_t> names_to_offsets;
152 std::vector<size_t> indices(sizes_and_strides.size(), 0);
153 generateNamesToOffsets(sizes_and_strides, 0, &indices,
154 &names_to_offsets);
155 return names_to_offsets;
156 }
157
172 std::vector<std::pair<size_t, size_t>> arraySizesAndStrides() const {
173 auto s = array_str();
174 if (s.empty()) {
175 return {};
176 }
177
178 std::size_t content_pos = npos;
179 std::vector<std::pair<size_t, size_t>> dims_;
180 for (size_t i = 0; i < s.size(); ++i) {
181 auto c = s[i];
182 if (c == '[') {
183 if (content_pos != npos) {
184 throw std::logic_error("Name has unbalanced brackets");
185 }
186 content_pos = i + 1;
187 } else if (c == ']') {
188 if (content_pos == npos) {
189 throw std::logic_error("Name has unbalanced brackets");
190 }
191 if (content_pos == i) {
192 throw std::logic_error("Name has nothing in brackets");
193 }
194 const auto &[size, stride] = sizeAndStride(
195 s.substr(content_pos, i - content_pos));
196 if (size == 0) {
197 throw std::logic_error("Dimension size is 0");
198 }
199 dims_.push_back({size, stride});
200 content_pos = npos;
201 }
202 }
203
204 if (content_pos != npos) {
205 throw std::logic_error("Name has unbalanced brackets");
206 }
207
208 return dims_;
209 }
210
211 private:
212#ifndef __GNUC__
213 // Microsoft Visual Studio 2022 treat these functions as non-constexpr and
214 // generates C3615 error
215 static constexpr bool isalpha(value_type c) {
216 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
217 }
218
219 static constexpr bool isalnum(value_type c) {
220 return isalpha(c) || (c >= '0' && c <= '9');
221 }
222#endif
223
237 std::pair<size_t, size_t> sizeAndStride(std::string_view s) const {
238 auto stride_pos = s.find(" stride ");
239 size_t size;
240 size_t stride = 0;
241
242 try {
243 if (stride_pos != npos) {
244 size = std::stoi(s.substr(0, stride_pos).data());
245 stride = std::stoi(s.substr(stride_pos + 8).data());
246 } else {
247 if (s.find_first_not_of("0123456789") != npos) {
248 throw std::invalid_argument("non-digit character");
249 }
250 size = std::stoi(s.data());
251 }
252 } catch (const std::exception &e) {
253 throw std::invalid_argument(
254 std::string("Array contents are malformed: ") + e.what());
255 }
256
257 return {size, stride};
258 }
259
284 void generateNamesToOffsets(const std::vector<std::pair<size_t, size_t>>
285 &dims_info,
286 size_t current_dim,
287 std::vector<size_t> *indices,
288 std::map<std::string, size_t>
289 *names_to_offsets) const {
290 if (current_dim == dims_info.size()) {
291 // We have reached the innermost dimension, so generate the name
292 // and offset and add it to the vector
293 std::string name {base_name()};
294 size_t offset = 0;
295 for (size_t i = 0; i < indices->size(); i++) {
296 name += "[" + std::to_string((*indices)[i]) + "]";
297 offset += (*indices)[i] * dims_info[i].second;
298 }
299 (*names_to_offsets)[name] = offset;
300 } else {
301 // Iterate over each index of the current dimension and recurse
302 for (size_t i = 0; i < dims_info[current_dim].first; i++) {
303 (*indices)[current_dim] = i;
304 generateNamesToOffsets(dims_info, current_dim + 1,
305 indices, names_to_offsets);
306 }
307 }
308 }
309};
310
311} // namespace detail
312} // namespace simics
313
314#endif
Represents name of a bank/register/field.
Definition: hierarchical-object-name.h:44
std::map< std::string, size_t > arrayNamesToOffsets(size_t width) const
Generates a mapping of array names to their corresponding memory offsets.
Definition: hierarchical-object-name.h:126
std::vector< std::pair< size_t, size_t > > arraySizesAndStrides() const
Parses a string representation of array dimensions to extract sizes and strides.
Definition: hierarchical-object-name.h:172
constexpr std::string_view array_str() const
Definition: hierarchical-object-name.h:104
static constexpr void validate_name(std::string_view name)
Validates the format of a name, ensuring it adheres to specific rules.
Definition: hierarchical-object-name.h:74
constexpr HierarchicalObjectName(const HierarchicalObjectName &other) noexcept=default
constexpr HierarchicalObjectName(const_pointer s)
Definition: hierarchical-object-name.h:54
constexpr HierarchicalObjectName(const_pointer s, size_type count)
Definition: hierarchical-object-name.h:50
constexpr HierarchicalObjectName() noexcept
Definition: hierarchical-object-name.h:46
constexpr std::string_view base_name() const
Definition: hierarchical-object-name.h:99
Definition: after-bank.h:33
Definition: common-types.h:66