ImpactX
Loading...
Searching...
No Matches
dynamicdata.H
Go to the documentation of this file.
1/* Copyright 2022-2026 The Regents of the University of California, through Lawrence
2 * Berkeley National Laboratory (subject to receipt of any required
3 * approvals from the U.S. Dept. of Energy). All rights reserved.
4 *
5 * This file is part of ImpactX.
6 *
7 * Authors: Axel Huebl
8 * License: BSD-3-Clause-LBNL
9 */
10#ifndef IMPACTX_ELEMENTS_MIXIN_DYNAMICDATA_H
11#define IMPACTX_ELEMENTS_MIXIN_DYNAMICDATA_H
12
13#include "impactx_export.H"
14
15#include <AMReX_Gpu.H>
16
17#include <map>
18#include <memory>
19#include <stdexcept>
20#include <string>
21#include <type_traits>
22#include <vector>
23
24
26{
27
52 template<typename T>
54 {
55 using DataType = T;
56
57 // Storage for the registry's state.
58 //
59 // Declared here as plain `static` members and defined out-of-line below
60 // (rather than `inline static ... = init;`) for two reasons:
61 //
62 // 1. NVCC 12.2 + C++20 evaluates the default-initializer of an
63 // `inline static` data member during implicit instantiation of the
64 // enclosing class template (any reference such as
65 // `DynamicData::get(id)` from an element header triggers it). With
66 // a `std::map<int, std::shared_ptr<T>>` value type that fails as
67 // "incomplete type is not allowed" on the brace-initializer. A
68 // declaration with no initializer sidesteps this entirely; the
69 // out-of-line definitions are only processed when an explicit
70 // instantiation actually requests them.
71 // 2. Combined with `extern template struct` in element headers and
72 // `template struct` in the corresponding .cpp, this still provides
73 // exactly one strong definition per element type. With
74 // `IMPACTX_EXPORT` the resulting symbol has default visibility, so
75 // downstream shared libraries built with `-fvisibility=hidden`
76 // and/or LTO (e.g. the Python bindings module) resolve to that one
77 // definition at load time even if they re-instantiate the
78 // `emplace<Args...>` member template locally. The previous
79 // function-local-static design (PR #1368) produced a hidden
80 // duplicate per DSO via the inlined accessor body inside `emplace`
81 // and caused emplace/get to disagree across module boundaries.
82 IMPACTX_EXPORT static int s_next_id;
83 IMPACTX_EXPORT static std::map<int, std::shared_ptr<T>> s_registry;
84
85 static int& next_id () { return s_next_id; }
86 static std::map<int, std::shared_ptr<T>>& registry () { return s_registry; }
87
89 static int allocate_id () { return next_id()++; }
90
97 static std::shared_ptr<T> const &
98 get (int id)
99 {
100 auto& reg = registry();
101 auto it = reg.find(id);
102 if (it == reg.end() || !it->second)
103 throw std::runtime_error(
104 "GPUDataRegistry::get failed for id=" + std::to_string(id));
105 return it->second;
106 }
107
113 static void store (int id, std::shared_ptr<T> data)
114 {
115 registry()[id] = std::move(data);
116 }
117
124 template<typename... Args>
125 static T& emplace (int id, Args&&... args)
126 {
127 auto ptr = std::shared_ptr<T>(new T{std::forward<Args>(args)...}); // NOLINT(modernize-make-shared)
128 registry()[id] = ptr;
129 return *ptr;
130 }
131
133 static void clear ()
134 {
135 registry().clear();
136 next_id() = 0;
137 }
138 };
139
140 // Out-of-class template definitions for the static data members declared
141 // inside `GPUDataRegistry`. These are deliberately not `inline static
142 // ... = init;` inside the class: see the comment on the declarations for
143 // the NVCC 12.2 + C++20 reason. Each element type gets exactly one strong
144 // definition per program via `IMPACTX_GPUDATA_INSTANTIATE` in its .cpp.
145 template<typename T>
147
148 template<typename T>
149 std::map<int, std::shared_ptr<T>> GPUDataRegistry<T>::s_registry;
150
151} // namespace impactx::elements::mixin
152
153
169#define IMPACTX_GPUDATA_EXTERN(ElementType) \
170 extern template struct impactx::elements::mixin::GPUDataRegistry< \
171 ElementType::DynamicData::DataType>;
172
180#define IMPACTX_GPUDATA_INSTANTIATE(ElementType) \
181 template struct impactx::elements::mixin::GPUDataRegistry< \
182 ElementType::DynamicData::DataType>;
183
184#endif // IMPACTX_ELEMENTS_MIXIN_DYNAMICDATA_H
Definition alignment.H:23
static void store(int id, std::shared_ptr< T > data)
Definition dynamicdata.H:113
static IMPACTX_EXPORT std::map< int, std::shared_ptr< CFbendCoefficients > > s_registry
Definition dynamicdata.H:83
static std::map< int, std::shared_ptr< T > > & registry()
Definition dynamicdata.H:86
static std::shared_ptr< T > const & get(int id)
Definition dynamicdata.H:98
static int allocate_id()
Definition dynamicdata.H:89
static T & emplace(int id, Args &&... args)
Definition dynamicdata.H:125
static int & next_id()
Definition dynamicdata.H:85
CFbendCoefficients DataType
Definition dynamicdata.H:55
static IMPACTX_EXPORT int s_next_id
Definition dynamicdata.H:82
static void clear()
Definition dynamicdata.H:133