Low-Level Abstraction of Memory Access
StructName.hpp
Go to the documentation of this file.
1 // Copyright 2022 Bernhard Manfred Gruber
2 // SPDX-License-Identifier: MPL-2.0
3 
4 #pragma once
5 
6 #include "Core.hpp"
7 
8 #include <stdexcept>
9 #include <string_view>
10 
11 namespace llama
12 {
13  namespace internal
14  {
15  // TODO(bgruber): just use std::copy which became constexpr in C++20
16  template<typename In, typename Out>
17  constexpr auto constexprCopy(In f, In l, Out d) -> Out
18  {
19  while(f != l)
20  *d++ = *f++;
21  return d;
22  }
23 
24  // TODO(bgruber): just use std::search which became constexpr in C++20
25  // from: https://en.cppreference.com/w/cpp/algorithm/search
26  template<class ForwardIt1, class ForwardIt2>
27  constexpr auto constexprSearch(ForwardIt1 first, ForwardIt1 last, ForwardIt2 sFirst, ForwardIt2 sLast)
28  -> ForwardIt1
29  {
30  while(true)
31  {
32  ForwardIt1 it = first;
33  for(ForwardIt2 sIt = sFirst;; ++it, ++sIt)
34  {
35  if(sIt == sLast)
36  return first;
37  if(it == last)
38  return last;
39  if(!(*it == *sIt))
40  break;
41  }
42  ++first;
43  }
44  }
45 
46  // TODO(bgruber): just use std::remove_copy which became constexpr in C++20
47  // from: https://en.cppreference.com/w/cpp/algorithm/remove_copy
48  template<class InputIt, class OutputIt, class T>
49  constexpr auto constexprRemoveCopy(InputIt first, InputIt last, OutputIt d_first, const T& value) -> OutputIt
50  {
51  for(; first != last; ++first)
52  {
53  if(!(*first == value))
54  {
55  *d_first++ = *first;
56  }
57  }
58  return d_first;
59  }
60 
61  // TODO(bgruber): just use std::count which became constexpr in C++20
62  // from: https://en.cppreference.com/w/cpp/algorithm/count
63  template<class InputIt, class T>
64  auto constexprCount(InputIt first, InputIt last, const T& value) ->
65  typename std::iterator_traits<InputIt>::difference_type
66  {
67  typename std::iterator_traits<InputIt>::difference_type ret = 0;
68  for(; first != last; ++first)
69  {
70  if(*first == value)
71  {
72  ret++;
73  }
74  }
75  return ret;
76  }
77 
78  template<std::size_t NewSize, typename T, std::size_t N>
79  constexpr auto resizeArray(Array<T, N> a)
80  {
82  constexprCopy(a.begin(), a.begin() + NewSize, r.begin());
83  return r;
84  }
85 
86  template<typename T>
87  constexpr auto typeNameAsArray()
88  {
89  // adapted from Matthew Rodusek:
90  // https://bitwizeshift.github.io/posts/2021/03/09/getting-an-unmangled-type-name-at-compile-time/
91  //
92  // Boost Software License - Version 1.0 - August 17th, 2003
93  //
94  // Permission is hereby granted, free of charge, to any person or organization
95  // obtaining a copy of the software and accompanying documentation covered by
96  // this license (the "Software") to use, reproduce, display, distribute,
97  // execute, and transmit the Software, and to prepare derivative works of the
98  // Software, and to permit third-parties to whom the Software is furnished to
99  // do so, all subject to the following:
100  //
101  // The copyright notices in the Software and this entire statement, including
102  // the above license grant, this restriction and the following disclaimer,
103  // must be included in all copies of the Software, in whole or in part, and
104  // all derivative works of the Software, unless such copies or derivative
105  // works are solely in the form of machine-executable object code generated by
106  // a source language processor.
107  //
108  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
109  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
110  // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
111  // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
112  // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
113  // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
114  // DEALINGS IN THE SOFTWARE.
115 
116 #if defined(__clang__)
117  constexpr auto prefix = std::string_view{"[T = "};
118  constexpr auto suffix = std::string_view{"]"};
119  constexpr auto function = std::string_view{__PRETTY_FUNCTION__};
120 #elif defined(__GNUC__)
121  constexpr auto prefix = std::string_view{"with T = "};
122  constexpr auto suffix = std::string_view{"]"};
123  constexpr auto function = std::string_view{__PRETTY_FUNCTION__};
124 #elif defined(_MSC_VER)
125  constexpr auto prefix = std::string_view{"typeNameAsArray<"};
126  constexpr auto suffix = std::string_view{">(void)"};
127  constexpr auto function = std::string_view{__FUNCSIG__};
128 #else
129 # warning Unsupported compiler
130  constexpr auto prefix = std::string_view{};
131  constexpr auto suffix = std::string_view{};
132  constexpr auto function = std::string_view{};
133 #endif
134 
135  constexpr auto start = function.find(prefix) + prefix.size();
136  constexpr auto end = function.rfind(suffix);
137  static_assert(start <= end);
138 
139  constexpr auto name = function.substr(start, (end - start));
140 
141  constexpr auto arrAndSize = [&]() constexpr
142  {
143  Array<char, name.size()> nameArray{};
144  constexprCopy(name.begin(), name.end(), nameArray.begin());
145 
146 #ifdef _MSC_VER
147  // MSVC 19.32 runs into a syntax error if we just capture nameArray. Passing it as argument is a
148  // workaround. Applies to the following lambdas.
149 
150  // strip "struct " and "class ".
151  auto removeAllOccurences = [](auto& nameArray, std::size_t size, std::string_view str) constexpr
152  {
153  auto e = nameArray.begin() + size;
154  while(true)
155  {
156  auto it = constexprSearch(nameArray.begin(), e, str.begin(), str.end());
157  if(it == e)
158  break;
159  constexprCopy(it + str.size(), e, it);
160  e -= str.size();
161  }
162  return e - nameArray.begin();
163  };
164 
165  auto size = removeAllOccurences(nameArray, nameArray.size(), std::string_view{"struct "});
166  size = removeAllOccurences(nameArray, size, std::string_view{"class "});
167 #else
168  auto size = nameArray.size();
169 #endif
170 
171  if(size > 3)
172  {
173  // remove spaces between closing template angle brackets and after commas
174  auto e = nameArray.begin() + size;
175  for(auto b = nameArray.begin(); b < e - 2; b++)
176  {
177  if((b[0] == '>' && b[1] == ' ' && b[2] == '>') || (b[0] == ',' && b[1] == ' '))
178  {
179  constexprCopy(b + 2, e, b + 1);
180  e--;
181  }
182  }
183  size = e - nameArray.begin();
184  }
185 
186  return std::pair{nameArray, size};
187  }();
188 
189  return resizeArray<arrAndSize.second>(arrAndSize.first);
190  }
191 
192  template<typename T>
193  inline constexpr auto typeNameStorage = typeNameAsArray<T>();
194  } // namespace internal
195 
197  template<typename T>
198  inline constexpr auto qualifiedTypeName = []
199  {
200  constexpr auto& value = internal::typeNameStorage<T>;
201  return std::string_view{value.data(), value.size()};
202  }();
203 
204  namespace internal
205  {
206  constexpr auto isIdentChar(char c) -> bool
207  {
208  if(c >= 'A' && c <= 'Z')
209  return true;
210  if(c >= 'a' && c <= 'z')
211  return true;
212  if(c >= '0' && c <= '9')
213  return true;
214  if(c == '_')
215  return true;
216  return false;
217  }
218 
219  template<typename T>
220  inline constexpr auto structNameStorage = []() constexpr
221  {
222  // strip namespace qualifiers before type names
223  constexpr auto arrAndSize = []() constexpr
224  {
225  auto s = internal::typeNameStorage<T>;
226  auto b = s.begin();
227  auto e = s.end();
228 
229 #if defined(__clang__)
230  constexpr auto anonNs = std::string_view{"(anonymous namespace)::"};
231 #elif defined(__NVCOMPILER)
232  constexpr auto anonNs = std::string_view{"<unnamed>::"};
233 #elif defined(__GNUG__)
234  constexpr auto anonNs = std::string_view{"{anonymous}::"};
235 #elif defined(_MSC_VER)
236  constexpr auto anonNs = std::string_view{"`anonymous-namespace'::"};
237 #else
238  constexpr auto anonNs = std::string_view{"@"}; // just anything we won't find
239 #endif
240  std::size_t pos = 0;
241  while((pos = std::string_view(b, e - b).find(anonNs)) != std::string::npos)
242  {
243  constexprCopy(b + pos + anonNs.size(), e, b + pos);
244  e -= anonNs.size();
245  }
246 
247  while(true)
248  {
249  // find iterator to after "::"
250  auto l = b;
251  while(l + 1 < e && !(l[0] == ':' && l[1] == ':'))
252  l++;
253  if(l + 1 == e)
254  break;
255  l += 2;
256 
257  // find iterator to first identifier char before "::"
258  auto f = l - 3; // start at first char before "::"
259  while(s.begin() < f && isIdentChar(f[-1]))
260  f--;
261 
262  // cut out [f:l[
263  constexprCopy(l, e, f);
264  e -= (l - f);
265  b = f;
266  }
267 
268  return std::pair{s, e - s.begin()};
269  }();
270 
271  return resizeArray<arrAndSize.second>(arrAndSize.first);
272  }();
273  } // namespace internal
274 
276  template<typename T>
277  constexpr auto structName(T = {}) -> std::string_view
278  {
279  constexpr auto& value = internal::structNameStorage<T>;
280  return std::string_view{&value[0], value.size()};
281  }
282 
283  namespace internal
284  {
285  constexpr auto intToStrSize(std::size_t s)
286  {
287  std::size_t len = 1;
288  while(s >= 10)
289  {
290  len++;
291  s /= 10;
292  }
293  return len;
294  }
295 
296  template<typename RecordDim, std::size_t... Coords>
297  LLAMA_ACC inline constexpr auto recordCoordTagsStorage = []() constexpr
298  {
299  using Tags = GetTags<RecordDim, RecordCoord<Coords...>>;
300 
301  // precompute char array size
302  constexpr auto size = [&]() constexpr
303  {
304  std::size_t s = 0;
305  mp_for_each_inline<Tags>(
306  [&](auto tag)
307  {
308  using Tag = decltype(tag);
309  if constexpr(isRecordCoord<Tag>)
310  {
311  // handle array indices
312  static_assert(Tag::size == 1);
313  s += 2; // for the '[' and ']'
314  s += intToStrSize(Tag::front);
315  }
316  else
317  {
318  if(s != 0)
319  s++; // for the '.'s
320  s += structName(tag).size();
321  }
322  });
323  return s;
324  }();
326  auto it = a.begin();
327 
328  mp_for_each_inline<Tags>(
329  [&](auto tag) constexpr
330  {
331  using Tag = decltype(tag);
332  if constexpr(isRecordCoord<Tag>)
333  {
334  auto n = Tag::front;
335  *it = '[';
336  it++;
337  it += intToStrSize(n);
338  auto it2 = it; // take copy because we write number backward
339  do // NOLINT(cppcoreguidelines-avoid-do-while)
340  {
341  it2--;
342  *it2 = '0' + n % 10;
343  n /= 10;
344  } while(n != 0);
345  *it = ']';
346  it++;
347  }
348  else
349  {
350  if(it != a.begin())
351  {
352  *it = '.';
353  it++;
354  }
355  constexpr auto sn = structName(Tag{});
356  constexprCopy(sn.begin(), sn.end(), it);
357  it += sn.size();
358  }
359  });
360 
361  if(!a.empty() && a.back() == 0)
362  throw std::logic_error{"Implementation error: Array should have been completely overwritten."};
363 
364  return a;
365  }();
366  } // namespace internal
367 
371  template<typename RecordDim, std::size_t... Coords>
372  constexpr auto prettyRecordCoord(RecordCoord<Coords...> = {}) -> std::string_view
373  {
374  constexpr auto& value = internal::recordCoordTagsStorage<RecordDim, Coords...>;
375  return std::string_view{value.data(), value.size()};
376  }
377 
379  template<typename RecordDim>
380  constexpr auto prettyRecordCoord(RecordCoord<>) -> std::string_view
381  {
382  return {};
383  }
384 } // namespace llama
#define LLAMA_EXPORT
Definition: macros.hpp:192
#define LLAMA_ACC
Definition: macros.hpp:77
constexpr auto constexprSearch(ForwardIt1 first, ForwardIt1 last, ForwardIt2 sFirst, ForwardIt2 sLast) -> ForwardIt1
Definition: StructName.hpp:27
auto constexprCount(InputIt first, InputIt last, const T &value) -> typename std::iterator_traits< InputIt >::difference_type
Definition: StructName.hpp:64
constexpr auto constexprCopy(In f, In l, Out d) -> Out
Definition: StructName.hpp:17
constexpr auto structNameStorage
Definition: StructName.hpp:220
constexpr auto resizeArray(Array< T, N > a)
Definition: StructName.hpp:79
constexpr auto typeNameStorage
Definition: StructName.hpp:193
constexpr auto typeNameAsArray()
Definition: StructName.hpp:87
constexpr auto isIdentChar(char c) -> bool
Definition: StructName.hpp:206
constexpr auto recordCoordTagsStorage
Definition: StructName.hpp:297
constexpr auto intToStrSize(std::size_t s)
Definition: StructName.hpp:285
constexpr auto constexprRemoveCopy(InputIt first, InputIt last, OutputIt d_first, const T &value) -> OutputIt
Definition: StructName.hpp:49
constexpr auto qualifiedTypeName
Definition: StructName.hpp:198
typename internal::GetTagsImpl< RecordDim, RecordCoord >::type GetTags
Definition: Core.hpp:233
constexpr auto structName(T={}) -> std::string_view
Definition: StructName.hpp:277
constexpr auto prettyRecordCoord(RecordCoord< Coords... >={}) -> std::string_view
Definition: StructName.hpp:372
constexpr auto begin() -> T *
Definition: Array.hpp:35
constexpr auto size() const
Definition: Array.hpp:25