Low-Level Abstraction of Memory Access
Core.hpp
Go to the documentation of this file.
1 // Copyright 2023 Alexander Matthes, Bernhard Manfred Gruber
2 // SPDX-License-Identifier: MPL-2.0
3 
4 #pragma once
5 
6 #include "ArrayExtents.hpp"
7 #include "Meta.hpp"
8 #include "RecordCoord.hpp"
9 
10 #include <string>
11 #include <type_traits>
12 #if __has_include(<boost/describe/members.hpp>)
13 # include <boost/describe/members.hpp>
14 #endif
15 
16 namespace llama
17 {
20  struct NoName
21  {
22  };
23 
27  template<typename T>
28  inline constexpr bool isAllowedFieldType = std::is_trivially_destructible_v<T>;
29 
38  template<typename Tag, typename Type>
39  struct Field
40  {
41  static_assert(isAllowedFieldType<Type>, "This field's type is not allowed");
42  };
43 
45  template<typename T>
46  inline constexpr bool isField = false;
47 
49  template<typename Tag, typename Type>
50  inline constexpr bool isField<Field<Tag, Type>> = true;
51 
54  template<typename... Fields>
55 #if __cpp_concepts
56  // Cannot use a fold expression here, because clang/nvcc/icx cannot handle more than 256 arguments.
57  // If you get an error here, then you passed a type which is not llama::Field as argument to Record
58  requires(mp_all<mp_bool<isField<Fields>>...>::value)
59 #endif
60  struct Record
61  {
62  };
63 
64 #if __cpp_nontype_template_args >= 201911L && !defined(__EDG__)
66 # define LLAMA_HAS_STRING_FIELDS
67 
68  namespace internal
69  {
70  // N includes the char to store the null-terminator
71  template<std::size_t N>
72  struct FixedString
73  {
74  constexpr FixedString(const char* str)
75  {
76  std::copy(str, str + N, data);
77  }
78 
79  char data[N];
80  };
81 
82  template<std::size_t N>
83  FixedString(const char (&str)[N]) -> FixedString<N>;
84 
85  template<FixedString Name>
86  struct StringTag
87  {
88  };
89  } // namespace internal
90 
91  inline namespace literals
92  {
95  template<internal::FixedString Name>
96  auto operator"" _Name()
97  {
98  return internal::StringTag<Name>{};
99  }
100  } // namespace literals
101 
105  template<internal::FixedString Tag, typename Type>
106  using NamedField = Field<internal::StringTag<Tag>, Type>;
107 
108 # if __has_include(<boost/describe/members.hpp>)
110 # define LLAMA_CAN_REFLECT_RECORD_DIM
111  namespace internal
112  {
113  template<typename T>
114  auto reflectToRecordDim();
115 
116  template<class C, typename T>
117  auto memberPointerPointeeType(T C::*) -> T;
118 
119  constexpr auto constexpr_strlen(const char* s)
120  {
121  const char* end = s;
122  while(*end != 0)
123  end++;
124  return end - s;
125  }
126 
127  template<typename Member>
128  using MakeFieldFromMemberDescriptor = NamedField<
129  FixedString<constexpr_strlen(Member::name) + 1>(Member::name),
130  decltype(reflectToRecordDim<decltype(memberPointerPointeeType(Member::pointer))>())>;
131 
132  template<typename T>
133  auto reflectToRecordDim()
134  {
135  if constexpr(boost::describe::has_describe_members<T>::value)
136  {
137  using MemberList = boost::describe::describe_members<T, boost::describe::mod_public>;
138  return mp_rename<mp_transform<MakeFieldFromMemberDescriptor, MemberList>, llama::Record>{};
139  }
140  else
141  return T{};
142  }
143  } // namespace internal
144 
147  template<typename T>
148  using ReflectToRecordDim = decltype(internal::reflectToRecordDim<T>());
149 # endif
150 #endif
151 
153  template<typename T>
154  struct NrAndOffset
155  {
156  T nr;
158 
159  friend auto operator<<(std::ostream& os, const NrAndOffset& value) -> std::ostream&
160  {
161  return os << "NrAndOffset{" << value.nr << ", " << value.offset << "}";
162  }
163  };
164 
166  template<typename Int>
168 
170  template<typename TA, typename TB>
171  auto operator==(const NrAndOffset<TA>& a, const NrAndOffset<TB>& b) -> bool
172  {
173  return a.nr == b.nr && a.offset == b.offset;
174  }
175 
177  template<typename TA, typename TB>
178  auto operator!=(const NrAndOffset<TA>& a, const NrAndOffset<TB>& b) -> bool
179  {
180  return !(a == b);
181  }
182 
185  template<typename Field>
186  using GetFieldTag = mp_first<Field>;
187 
190  template<typename Field>
191  using GetFieldType = mp_second<Field>;
192 
194  template<typename T>
195  inline constexpr auto isRecord = false;
196 
198  template<typename... Fields>
199  inline constexpr auto isRecord<Record<Fields...>> = true;
200 
201  namespace internal
202  {
203  template<typename RecordDim, typename RecordCoord>
204  struct GetTagsImpl;
205 
206  template<typename... Fields, std::size_t FirstCoord, std::size_t... Coords>
207  struct GetTagsImpl<Record<Fields...>, RecordCoord<FirstCoord, Coords...>>
208  {
209  using Field = mp_at_c<mp_list<Fields...>, FirstCoord>;
212  using type = mp_push_front<typename GetTagsImpl<ChildType, RecordCoord<Coords...>>::type, ChildTag>;
213  };
214 
215  template<typename ChildType, std::size_t Count, std::size_t FirstCoord, std::size_t... Coords>
216  struct GetTagsImpl<ChildType[Count], RecordCoord<FirstCoord, Coords...>>
217  {
219  using type = mp_push_front<typename GetTagsImpl<ChildType, RecordCoord<Coords...>>::type, ChildTag>;
220  };
221 
222  template<typename T>
224  {
225  using type = mp_list<>;
226  };
227  } // namespace internal
228 
232  template<typename RecordDim, typename RecordCoord>
234 
235  namespace internal
236  {
237  template<typename RecordDim, typename RecordCoord>
238  struct GetTagImpl
239  {
240  using type = mp_back<GetTags<RecordDim, RecordCoord>>;
241  };
242 
243  template<typename RecordDim>
244  struct GetTagImpl<RecordDim, RecordCoord<>>
245  {
246  using type = NoName;
247  };
248  } // namespace internal
249 
252  template<typename RecordDim, typename RecordCoord>
254 
263  template<typename RecordDimA, typename RecordCoordA, typename RecordDimB, typename RecordCoordB>
264  inline constexpr auto hasSameTags = []() constexpr
265  {
266  if constexpr(RecordCoordA::size != RecordCoordB::size)
267  return false;
268  else if constexpr(RecordCoordA::size == 0 && RecordCoordB::size == 0)
269  return true;
270  else
271  return std::is_same_v<GetTags<RecordDimA, RecordCoordA>, GetTags<RecordDimB, RecordCoordB>>;
272  }();
273 
274  namespace internal
275  {
276  template<typename FieldList, typename Tag>
278  {
279  template<typename Field>
280  using HasTag = std::is_same<GetFieldTag<Field>, Tag>;
281 
282  static constexpr auto value = mp_find_if<FieldList, HasTag>::value;
283  };
284 
285  template<typename RecordDim, typename RecordCoord, typename... Tags>
287  {
288  static_assert(mp_size<RecordDim>::value != 0, "Tag combination is not valid");
289  };
290 
291  template<typename... Fields, std::size_t... ResultCoords, typename FirstTag, typename... Tags>
292  struct GetCoordFromTagsImpl<Record<Fields...>, RecordCoord<ResultCoords...>, FirstTag, Tags...>
293  {
294  static constexpr auto tagIndex = FindFieldByTag<mp_list<Fields...>, FirstTag>::value;
295  static_assert(
296  tagIndex < sizeof...(Fields),
297  "FirstTag was not found inside this Record. Does your record dimension contain the tag you access "
298  "with?");
299 
300  using ChildType = GetFieldType<mp_at_c<Record<Fields...>, tagIndex>>;
301 
302  using type =
303  typename GetCoordFromTagsImpl<ChildType, RecordCoord<ResultCoords..., tagIndex>, Tags...>::type;
304  };
305 
306  template<
307  typename ChildType,
308  std::size_t Count,
309  std::size_t... ResultCoords,
310  typename FirstTag,
311  typename... Tags>
312  struct GetCoordFromTagsImpl<ChildType[Count], RecordCoord<ResultCoords...>, FirstTag, Tags...>
313  {
314  static_assert(isRecordCoord<FirstTag>, "Please use a RecordCoord<I> to index into static arrays");
315  static_assert(FirstTag::size == 1, "Expected RecordCoord with 1 coordinate");
316  static_assert(FirstTag::front < Count, "Index out of bounds");
317 
318  using type =
319  typename GetCoordFromTagsImpl<ChildType, RecordCoord<ResultCoords..., FirstTag::front>, Tags...>::type;
320  };
321 
322  template<typename RecordDim, typename RecordCoord>
324  {
325  using type = RecordCoord;
326  };
327 
328  // unpack a list of tags
329  template<typename... Fields, typename... Tags>
330  struct GetCoordFromTagsImpl<Record<Fields...>, RecordCoord<>, mp_list<Tags...>>
331  : GetCoordFromTagsImpl<Record<Fields...>, RecordCoord<>, Tags...>
332  {
333  };
334 
335  template<typename ChildType, std::size_t Count, typename... Tags>
336  struct GetCoordFromTagsImpl<ChildType[Count], RecordCoord<>, mp_list<Tags...>>
337  : GetCoordFromTagsImpl<ChildType[Count], RecordCoord<>, Tags...>
338  {
339  };
340 
341  // pass through a RecordCoord
342  template<typename... Fields, std::size_t... RCs>
343  struct GetCoordFromTagsImpl<Record<Fields...>, RecordCoord<>, RecordCoord<RCs...>>
344  {
345  using type = RecordCoord<RCs...>;
346  };
347  } // namespace internal
348 
352  template<typename RecordDim, typename... TagsOrTagList>
354 
355  namespace internal
356  {
357  template<typename RecordDim, typename... RecordCoordOrTags>
358  struct GetTypeImpl
359  {
360  using type = typename GetTypeImpl<RecordDim, GetCoordFromTags<RecordDim, RecordCoordOrTags...>>::type;
361  };
362 
363  template<typename... Children, std::size_t HeadCoord, std::size_t... TailCoords>
364  struct GetTypeImpl<Record<Children...>, RecordCoord<HeadCoord, TailCoords...>>
365  {
366  using ChildType = GetFieldType<mp_at_c<Record<Children...>, HeadCoord>>;
367  using type = typename GetTypeImpl<ChildType, RecordCoord<TailCoords...>>::type;
368  };
369 
370  template<typename ChildType, std::size_t N, std::size_t HeadCoord, std::size_t... TailCoords>
371  struct GetTypeImpl<ChildType[N], RecordCoord<HeadCoord, TailCoords...>>
372  {
373  using type = typename GetTypeImpl<ChildType, RecordCoord<TailCoords...>>::type;
374  };
375 
376  template<typename T>
378  {
379  static_assert(isAllowedFieldType<T>);
380  using type = T;
381  };
382  } // namespace internal
383 
387  template<typename RecordDim, typename... RecordCoordOrTags>
388  using GetType = typename internal::GetTypeImpl<RecordDim, RecordCoordOrTags...>::type;
389 
390  namespace internal
391  {
392  template<typename RecordDim, typename RecordCoord>
394 
395  template<typename T, std::size_t... RCs>
397  {
398  using type = mp_list<RecordCoord<RCs...>>;
399  };
400 
401  template<typename... Fields, std::size_t... RCs>
402  struct LeafRecordCoordsImpl<Record<Fields...>, RecordCoord<RCs...>>
403  {
404  template<std::size_t... Is>
405  static auto help(std::index_sequence<Is...>)
406  {
407  return mp_append<
409  }
410  using type = decltype(help(std::make_index_sequence<sizeof...(Fields)>{}));
411  };
412 
413  template<typename Child, std::size_t N, std::size_t... RCs>
414  struct LeafRecordCoordsImpl<Child[N], RecordCoord<RCs...>>
415  {
416  template<std::size_t... Is>
417  static auto help(std::index_sequence<Is...>)
418  {
419  return mp_append<typename LeafRecordCoordsImpl<Child, RecordCoord<RCs..., Is>>::type...>{};
420  }
421  using type = decltype(help(std::make_index_sequence<N>{}));
422  };
423  } // namespace internal
424 
427  template<typename RecordDim>
429 
436  template<typename RecordDim, typename Functor, std::size_t... Coords>
437  LLAMA_FN_HOST_ACC_INLINE constexpr void forEachLeafCoord(Functor&& functor, RecordCoord<Coords...> baseCoord)
438  {
440  mp_for_each_inline<LeafRecordCoords<GetType<RecordDim, RecordCoord<Coords...>>>>(
441  [&](auto innerCoord) LLAMA_LAMBDA_INLINE_WITH_SPECIFIERS(constexpr)
442  { std::forward<Functor>(functor)(cat(baseCoord, innerCoord)); });
444  }
445 
452  template<typename RecordDim, typename Functor, typename... Tags>
453  LLAMA_FN_HOST_ACC_INLINE constexpr void forEachLeafCoord(Functor&& functor, Tags... /*baseTags*/)
454  {
455  forEachLeafCoord<RecordDim>(std::forward<Functor>(functor), GetCoordFromTags<RecordDim, Tags...>{});
456  }
457 
458  namespace internal
459  {
460  template<typename T>
462  {
463  using type = mp_list<T>;
464  };
465 
466  template<typename... Fields>
467  struct FlattenRecordDimImpl<Record<Fields...>>
468  {
469  using type = mp_append<typename FlattenRecordDimImpl<GetFieldType<Fields>>::type...>;
470  };
471  template<typename Child, std::size_t N>
472  struct FlattenRecordDimImpl<Child[N]>
473  {
474  using type = mp_repeat_c<typename FlattenRecordDimImpl<Child>::type, N>;
475  };
476  } // namespace internal
477 
480  template<typename RecordDim>
482 
485  template<typename RecordDim>
486  inline constexpr std::size_t flatFieldCount = 1;
487 
489  template<typename... Children>
490  inline constexpr std::size_t flatFieldCount<Record<Children...>>
491  = (flatFieldCount<GetFieldType<Children>> + ... + 0);
492 
494  template<typename Child, std::size_t N>
495  inline constexpr std::size_t flatFieldCount<Child[N]> = flatFieldCount<Child> * N;
496 
497  namespace internal
498  {
499  template<std::size_t I, typename RecordDim>
500  inline constexpr std::size_t flatFieldCountBefore = 0;
501 
502  template<typename... Children>
503  inline constexpr std::size_t flatFieldCountBefore<0, Record<Children...>> = 0;
504 
505  // recursive formulation to benefit from template instantiation memoization
506  // this massively improves compilation time when this template is instantiated with a lot of different I
507  template<std::size_t I, typename... Children>
508  inline constexpr std::size_t flatFieldCountBefore<I, Record<Children...>>
509  = flatFieldCountBefore<I - 1, Record<Children...>>
510  + flatFieldCount<GetFieldType<mp_at_c<Record<Children...>, I - 1>>>;
511  } // namespace internal
512 
516  template<typename RecordDim, typename RecordCoord>
517  inline constexpr std::size_t flatRecordCoord = 0;
518 
520  template<typename T>
521  inline constexpr std::size_t flatRecordCoord<T, RecordCoord<>> = 0;
522 
524  template<typename... Children, std::size_t I, std::size_t... Is>
525  inline constexpr std::size_t flatRecordCoord<Record<Children...>, RecordCoord<I, Is...>>
526  = internal::flatFieldCountBefore<I, Record<Children...>>
527  + flatRecordCoord<GetFieldType<mp_at_c<Record<Children...>, I>>, RecordCoord<Is...>>;
528 
530  template<typename Child, std::size_t N, std::size_t I, std::size_t... Is>
531  inline constexpr std::size_t flatRecordCoord<Child[N], RecordCoord<I, Is...>>
532  = flatFieldCount<Child> * I + flatRecordCoord<Child, RecordCoord<Is...>>;
533 
534  namespace internal
535  {
536  template<typename TypeList>
537  constexpr auto flatAlignOfImpl()
538  {
539  std::size_t maxAlign = 0;
540  mp_for_each_inline<mp_transform<mp_identity, TypeList>>(
541  [&](auto e) constexpr
542  {
543  using T = typename decltype(e)::type;
544  maxAlign = std::max(maxAlign, alignof(T));
545  });
546  return maxAlign;
547  }
548  } // namespace internal
549 
553  template<typename TypeList>
554  inline constexpr std::size_t flatAlignOf = internal::flatAlignOfImpl<TypeList>();
555 
558  template<typename T>
559  inline constexpr std::size_t alignOf = alignof(T);
560 
564  template<typename... Fields>
565  inline constexpr std::size_t alignOf<Record<Fields...>> = flatAlignOf<FlatRecordDim<Record<Fields...>>>;
566 
569  template<typename Integral>
570  [[nodiscard]] LLAMA_FN_HOST_ACC_INLINE constexpr auto divCeil(Integral a, Integral b) -> Integral
571  {
572  return (a + b - 1) / b;
573  }
574 
577  template<typename Integral>
578  [[nodiscard]] LLAMA_FN_HOST_ACC_INLINE constexpr auto roundUpToMultiple(Integral n, Integral mult) -> Integral
579  {
580  return divCeil(n, mult) * mult;
581  }
582 
583  namespace internal
584  {
585  template<typename TypeList, bool Align, bool IncludeTailPadding>
586  constexpr auto sizeOfImpl() -> std::size_t
587  {
588  std::size_t size = 0;
589  std::size_t maxAlign = 0; // NOLINT(misc-const-correctness)
590  mp_for_each_inline<mp_transform<mp_identity, TypeList>>(
591  [&](auto e) constexpr
592  {
593  using T = typename decltype(e)::type;
594  if constexpr(Align)
595  {
596  size = roundUpToMultiple(size, alignof(T));
597  maxAlign = std::max(maxAlign, alignof(T));
598  }
599  // NOLINTNEXTLINE(readability-misleading-indentation)
600  size += sizeof(T);
601  });
602 
603  // final padding, so next struct can start right away
604  if constexpr(Align && IncludeTailPadding)
605  if(maxAlign > 0)
606  size = roundUpToMultiple(size, maxAlign); // TODO(bgruber): we could use flatAlignOf<TypeList>
607  // here, at the cost of more template instantiations
608  return size;
609  }
610 
611  template<typename TypeList, std::size_t I, bool Align>
612  constexpr auto offsetOfImplWorkaround() -> std::size_t;
613  } // namespace internal
614 
617  template<typename TypeList, bool Align, bool IncludeTailPadding = true>
618  inline constexpr std::size_t flatSizeOf = internal::sizeOfImpl<TypeList, Align, IncludeTailPadding>();
619 
622  template<typename T, bool Align = false, bool IncludeTailPadding = true>
623  inline constexpr std::size_t sizeOf = sizeof(T);
624 
627  template<typename... Fields, bool Align, bool IncludeTailPadding>
628  inline constexpr std::size_t sizeOf<Record<Fields...>, Align, IncludeTailPadding>
629  = flatSizeOf<FlatRecordDim<Record<Fields...>>, Align, IncludeTailPadding>;
630 
633  template<typename TypeList, std::size_t I, bool Align>
634  inline constexpr std::size_t flatOffsetOf = internal::offsetOfImplWorkaround<TypeList, I, Align>();
635 
636  namespace internal
637  {
638  // unfortunately, we cannot inline this function as an IILE, as MSVC complains:
639  // fatal error C1202: recursive type or function dependency context too complex
640  template<typename TypeList, std::size_t I, bool Align>
641  constexpr auto offsetOfImplWorkaround() -> std::size_t
642  {
643  if constexpr(I == 0)
644  return 0;
645  else
646  {
647  std::size_t offset // NOLINT(misc-const-correctness)
648  = flatOffsetOf<TypeList, I - 1, Align> + sizeof(mp_at_c<TypeList, I - 1>);
649  if constexpr(Align)
650  offset = roundUpToMultiple(offset, alignof(mp_at_c<TypeList, I>));
651  return offset;
652  }
653  }
654  } // namespace internal
655 
660  template<typename RecordDim, typename RecordCoord, bool Align = false>
661  inline constexpr std::size_t offsetOf
662  = flatOffsetOf<FlatRecordDim<RecordDim>, flatRecordCoord<RecordDim, RecordCoord>, Align>;
663 
664  namespace internal
665  {
666  // Such a class is also known as arraw_proxy: https://quuxplusone.github.io/blog/2019/02/06/arrow-proxy/
667  template<typename T>
669  {
670  T value;
671 
673  {
674  return &value;
675  }
676 
677  LLAMA_FN_HOST_ACC_INLINE auto operator->() const -> const T*
678  {
679  return &value;
680  }
681  };
682 
683  // TODO(bgruber): replace in C++20
684  template<class T>
685  struct IsBoundedArray : std::false_type
686  {
687  };
688 
689  template<class T, std::size_t N>
690  struct IsBoundedArray<T[N]> : std::true_type
691  {
692  };
693  } // namespace internal
694 
697  template<typename T>
698  inline constexpr bool isRecordDim = isRecord<T> || internal::IsBoundedArray<T>::value;
699 
700  namespace internal
701  {
702  template<typename Coord, typename T, template<typename, typename> typename TypeFunctor>
704  {
705  using type = TypeFunctor<Coord, T>;
706  };
707 
708  template<std::size_t... Is, typename... Fields, template<typename, typename> typename TypeFunctor>
709  struct TransformLeavesWithCoordImpl<RecordCoord<Is...>, Record<Fields...>, TypeFunctor>
710  {
711  template<std::size_t... Js>
712  static auto f(std::index_sequence<Js...>)
713  {
714  return Record<Field<
716  typename TransformLeavesWithCoordImpl<RecordCoord<Is..., Js>, GetFieldType<Fields>, TypeFunctor>::
717  type>...>{};
718  }
719 
720  using type = decltype(f(std::index_sequence_for<Fields...>{}));
721  };
722  template<std::size_t... Is, typename Child, std::size_t N, template<typename, typename> typename TypeFunctor>
723  struct TransformLeavesWithCoordImpl<RecordCoord<Is...>, Child[N], TypeFunctor>
724  {
725  template<std::size_t... Js>
726  static void f(std::index_sequence<Js...>)
727  {
728  static_assert(
729  mp_same<typename TransformLeavesWithCoordImpl<RecordCoord<Is..., Js>, Child, TypeFunctor>::
730  type...>::value,
731  "Leave transformations beneath an array node must return the same type");
732  }
733  using dummy = decltype(f(std::make_index_sequence<N>{}));
734 
735  using type = typename TransformLeavesWithCoordImpl<RecordCoord<Is..., 0>, Child, TypeFunctor>::type[N];
736  };
737 
738  template<template<typename> typename F>
740  {
741  template<typename A, typename B>
742  using fn = F<B>;
743  };
744  } // namespace internal
745 
749  template<typename RecordDim, template<typename, typename> typename FieldTypeFunctor>
751  typename internal::TransformLeavesWithCoordImpl<RecordCoord<>, RecordDim, FieldTypeFunctor>::type;
752 
756  template<typename RecordDim, template<typename> typename FieldTypeFunctor>
759 
760  namespace internal
761  {
762  // TODO(bgruber): we might implement this better by expanding a record dim into a list of tag lists and then
763  // computing a real set union of the two tag list lists
764 
765  template<typename A, typename B>
766  auto mergeRecordDimsImpl(mp_identity<A> a, mp_identity<B>)
767  {
768  static_assert(std::is_same_v<A, B>, "Cannot merge record and non-record or fields with different types");
769  return a;
770  }
771 
772  template<typename A, std::size_t NA, typename B, std::size_t NB>
773  auto mergeRecordDimsImpl([[maybe_unused]] mp_identity<A[NA]> a, [[maybe_unused]] mp_identity<B[NB]> b)
774  {
775  static_assert(std::is_same_v<A, B>, "Cannot merge arrays of different type");
776  if constexpr(NA < NB)
777  return b;
778  else
779  return a;
780  }
781 
782  template<typename... FieldsA>
783  auto mergeRecordDimsImpl(mp_identity<Record<FieldsA...>> a, mp_identity<Record<>>)
784  {
785  return a;
786  }
787 
788  template<
789  typename... FieldsA,
790  typename FieldB,
791  typename... FieldsB,
792  auto Pos = FindFieldByTag<Record<FieldsA...>, GetFieldTag<FieldB>>::value>
794  {
795  if constexpr(Pos == sizeof...(FieldsA))
796  {
797  return mergeRecordDimsImpl(
798  mp_identity<Record<FieldsA..., FieldB>>{},
799  mp_identity<Record<FieldsB...>>{});
800  }
801  else
802  {
803  using OldFieldA = mp_at_c<Record<FieldsA...>, Pos>;
804  using NewFieldA = Field<
806  typename decltype(mergeRecordDimsImpl(
807  mp_identity<GetFieldType<OldFieldA>>{},
808  mp_identity<GetFieldType<FieldB>>{}))::type>;
809  using NewRecordA = mp_replace_at_c<Record<FieldsA...>, Pos, NewFieldA>;
810  return mergeRecordDimsImpl(mp_identity<NewRecordA>{}, mp_identity<Record<FieldsB...>>{});
811  }
812  }
813  } // namespace internal
814 
817  template<typename RecordDimA, typename RecordDimB>
819  typename decltype(internal::mergeRecordDimsImpl(mp_identity<RecordDimA>{}, mp_identity<RecordDimB>{}))::type;
820 
823  template<typename FromT, typename ToT>
824  using CopyConst = std::conditional_t<std::is_const_v<FromT>, const ToT, ToT>;
825 
828  template<auto V>
829  using Constant = std::integral_constant<decltype(V), V>;
830 
831  namespace internal
832  {
833  template<typename T>
834  struct IsConstant : std::false_type
835  {
836  };
837 
838  template<typename T, T V>
839  struct IsConstant<std::integral_constant<T, V>> : std::true_type
840  {
841  };
842  } // namespace internal
843 
845  template<typename T>
847 
848  namespace internal
849  {
853  template<typename T, int I = 0>
854  struct BoxedValue
855  {
856  BoxedValue() = default;
857 
858  // we don't make this ctor explicit so a Value appearing in a ctor list can just be created by passing a T
859  // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
861  {
862  }
863 
864  LLAMA_FN_HOST_ACC_INLINE constexpr auto value() const
865  {
866  return val;
867  }
868 
869  private:
870  T val = {};
871  };
872 
873  template<auto V, int I>
874  struct BoxedValue<Constant<V>, I>
875  {
876  BoxedValue() = default;
877 
878  // we don't make this ctor explicit so a Value appearing in a ctor list can just be created by passing a T
879  // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
881  {
882  }
883 
884  LLAMA_FN_HOST_ACC_INLINE static constexpr auto value()
885  {
886  return V;
887  }
888  };
889  } // namespace internal
890 
892  struct PrettySize
893  {
894  double size;
895  const char* unit;
896  };
897 
901  inline auto prettySize(double size) -> PrettySize
902  {
903  static const char* unit[] = {"B ", "KB", "MB", "GB", "TB", "PB", "EB"};
904  unsigned unitIndex = 0;
905  while(size > 1000.0)
906  {
907  size /= 1000.0;
908  unitIndex++;
909  }
910  assert(unitIndex < std::size(unit));
911  return {size, unit[unitIndex]};
912  }
913 } // namespace llama
#define LLAMA_EXPORT
Definition: macros.hpp:192
#define LLAMA_LAMBDA_INLINE_WITH_SPECIFIERS(...)
Definition: macros.hpp:107
#define LLAMA_BEGIN_SUPPRESS_HOST_DEVICE_WARNING
Definition: macros.hpp:141
#define LLAMA_FN_HOST_ACC_INLINE
Definition: macros.hpp:96
#define LLAMA_END_SUPPRESS_HOST_DEVICE_WARNING
Definition: macros.hpp:153
constexpr std::size_t flatFieldCountBefore
Definition: Core.hpp:500
constexpr auto flatAlignOfImpl()
Definition: Core.hpp:537
constexpr auto offsetOfImplWorkaround() -> std::size_t
Definition: Core.hpp:641
auto mergeRecordDimsImpl(mp_identity< A > a, mp_identity< B >)
Definition: Core.hpp:766
constexpr auto sizeOfImpl() -> std::size_t
Definition: Core.hpp:586
std::integral_constant< decltype(V), V > Constant
Used as template argument to specify a constant/compile-time value.
Definition: Core.hpp:829
constexpr std::size_t flatFieldCount< Child[N]>
Definition: Core.hpp:495
typename internal::FlattenRecordDimImpl< RecordDim >::type FlatRecordDim
Returns a flat type list containing all leaf field types of the given record dimension.
Definition: Core.hpp:481
constexpr std::size_t sizeOf
The size of a type T.
Definition: Core.hpp:623
NrAndOffset(Int, Int) -> NrAndOffset< Int >
constexpr auto hasSameTags
Definition: Core.hpp:264
constexpr auto isRecord
Definition: Core.hpp:195
constexpr auto cat(RecordCoords...)
Concatenate a set of RecordCoords instances.
constexpr auto operator==(ArrayIndex< TA, Dim > a, ArrayIndex< TB, Dim > b) -> bool
typename internal::GetTagsImpl< RecordDim, RecordCoord >::type GetTags
Definition: Core.hpp:233
constexpr auto divCeil(Integral a, Integral b) -> Integral
Returns the ceiling of a / b.
Definition: Core.hpp:570
typename internal::GetTagImpl< RecordDim, RecordCoord >::type GetTag
Get the tag of the Field at a RecordCoord inside the record dimension tree.
Definition: Core.hpp:253
constexpr std::size_t flatRecordCoord
Definition: Core.hpp:517
constexpr std::size_t flatAlignOf
Definition: Core.hpp:554
constexpr void mp_for_each_inline(F &&f)
Like boost::mp11::mp_for_each, but marked with LLAMA_FN_HOST_ACC_INLINE.
Definition: Meta.hpp:59
constexpr bool isField
Definition: Core.hpp:46
mp_second< Field > GetFieldType
Get the type from a Field.
Definition: Core.hpp:191
constexpr std::size_t flatOffsetOf
The byte offset of an element in a type list ifs elements would be in a normal struct.
Definition: Core.hpp:634
TransformLeavesWithCoord< RecordDim, internal::MakePassSecond< FieldTypeFunctor >::template fn > TransformLeaves
Definition: Core.hpp:758
constexpr auto operator!=(ArrayIndex< TA, Dim > a, ArrayIndex< TB, Dim > b) -> bool
constexpr void forEachLeafCoord(Functor &&functor, RecordCoord< Coords... > baseCoord)
Definition: Core.hpp:437
constexpr std::size_t flatFieldCount
The total number of fields in the recursively expanded record dimension.
Definition: Core.hpp:486
std::conditional_t< std::is_const_v< FromT >, const ToT, ToT > CopyConst
Alias for ToT, adding const if FromT is const qualified.
Definition: Core.hpp:824
constexpr std::size_t offsetOf
Definition: Core.hpp:662
typename internal::TransformLeavesWithCoordImpl< RecordCoord<>, RecordDim, FieldTypeFunctor >::type TransformLeavesWithCoord
Definition: Core.hpp:751
typename internal::LeafRecordCoordsImpl< RecordDim, RecordCoord<> >::type LeafRecordCoords
Returns a flat type list containing all record coordinates to all leaves of the given record dimensio...
Definition: Core.hpp:428
void copy(const View< SrcMapping, SrcBlob > &srcView, View< DstMapping, DstBlob > &dstView, std::size_t threadId=0, std::size_t threadCount=1)
Definition: Copy.hpp:491
typename decltype(internal::mergeRecordDimsImpl(mp_identity< RecordDimA >{}, mp_identity< RecordDimB >{}))::type MergedRecordDims
Creates a merged record dimension, where duplicated, nested fields are unified.
Definition: Core.hpp:819
constexpr bool isRecordDim
True if the T is a record dimension. That is, T is either a llama::Record or a bounded array.
Definition: Core.hpp:698
constexpr auto roundUpToMultiple(Integral n, Integral mult) -> Integral
Returns the integral n rounded up to be a multiple of mult.
Definition: Core.hpp:578
typename internal::GetCoordFromTagsImpl< RecordDim, RecordCoord<>, TagsOrTagList... >::type GetCoordFromTags
Definition: Core.hpp:353
constexpr std::size_t flatSizeOf
The size of a type list if its elements would be in a normal struct.
Definition: Core.hpp:618
mp_first< Field > GetFieldTag
Get the tag from a Field.
Definition: Core.hpp:186
constexpr bool isAllowedFieldType
Tells whether the given type is allowed as a field type in LLAMA. Such types need to be trivially con...
Definition: Core.hpp:28
typename internal::GetTypeImpl< RecordDim, RecordCoordOrTags... >::type GetType
Definition: Core.hpp:388
constexpr bool isConstant
Definition: Core.hpp:846
constexpr std::size_t alignOf
The alignment of a type T.
Definition: Core.hpp:559
auto prettySize(double size) -> PrettySize
Definition: Core.hpp:901
Anonymous naming for a Field.
Definition: Core.hpp:21
friend auto operator<<(std::ostream &os, const NrAndOffset &value) -> std::ostream &
Definition: Core.hpp:159
const char * unit
Definition: Core.hpp:895
A type list of Fields which may be used to define a record dimension.
Definition: Core.hpp:61
constexpr auto value() const
Definition: Core.hpp:864
std::is_same< GetFieldTag< Field >, Tag > HasTag
Definition: Core.hpp:280
static constexpr auto value
Definition: Core.hpp:282
mp_repeat_c< typename FlattenRecordDimImpl< Child >::type, N > type
Definition: Core.hpp:474
mp_append< typename FlattenRecordDimImpl< GetFieldType< Fields > >::type... > type
Definition: Core.hpp:469
typename GetCoordFromTagsImpl< ChildType, RecordCoord< ResultCoords..., FirstTag::front >, Tags... >::type type
Definition: Core.hpp:319
typename GetCoordFromTagsImpl< ChildType, RecordCoord< ResultCoords..., tagIndex >, Tags... >::type type
Definition: Core.hpp:303
mp_back< GetTags< RecordDim, RecordCoord > > type
Definition: Core.hpp:240
mp_push_front< typename GetTagsImpl< ChildType, RecordCoord< Coords... > >::type, ChildTag > type
Definition: Core.hpp:219
mp_push_front< typename GetTagsImpl< ChildType, RecordCoord< Coords... > >::type, ChildTag > type
Definition: Core.hpp:212
typename GetTypeImpl< ChildType, RecordCoord< TailCoords... > >::type type
Definition: Core.hpp:373
typename GetTypeImpl< ChildType, RecordCoord< TailCoords... > >::type type
Definition: Core.hpp:367
GetFieldType< mp_at_c< Record< Children... >, HeadCoord > > ChildType
Definition: Core.hpp:366
typename GetTypeImpl< RecordDim, GetCoordFromTags< RecordDim, RecordCoordOrTags... > >::type type
Definition: Core.hpp:360
auto operator->() const -> const T *
Definition: Core.hpp:677
auto operator->() -> T *
Definition: Core.hpp:672
decltype(help(std::make_index_sequence< N >{})) type
Definition: Core.hpp:421
decltype(help(std::make_index_sequence< sizeof...(Fields)>{})) type
Definition: Core.hpp:410
typename TransformLeavesWithCoordImpl< RecordCoord< Is..., 0 >, Child, TypeFunctor >::type[N] type
Definition: Core.hpp:735