xref: /petsc/src/sys/objects/device/impls/impldevicebase.hpp (revision 0e6b6b5985dd9b1172860d21fb88bd3966bf7c54)
1*0e6b6b59SJacob Faibussowitsch #ifndef IMPLDEVICEBASE_HPP
2*0e6b6b59SJacob Faibussowitsch #define IMPLDEVICEBASE_HPP
3*0e6b6b59SJacob Faibussowitsch 
4*0e6b6b59SJacob Faibussowitsch #if defined(__cplusplus)
5*0e6b6b59SJacob Faibussowitsch #include <petsc/private/deviceimpl.h>
6*0e6b6b59SJacob Faibussowitsch #include <petsc/private/viewerimpl.h>
7*0e6b6b59SJacob Faibussowitsch 
8*0e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/crtp.hpp>
9*0e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/type_traits.hpp>
10*0e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/utility.hpp>
11*0e6b6b59SJacob Faibussowitsch #include <petsc/private/cpp/array.hpp>
12*0e6b6b59SJacob Faibussowitsch 
13*0e6b6b59SJacob Faibussowitsch #include <cstring> // for std::strlen
14*0e6b6b59SJacob Faibussowitsch 
15*0e6b6b59SJacob Faibussowitsch namespace Petsc {
16*0e6b6b59SJacob Faibussowitsch 
17*0e6b6b59SJacob Faibussowitsch namespace device {
18*0e6b6b59SJacob Faibussowitsch 
19*0e6b6b59SJacob Faibussowitsch namespace impl {
20*0e6b6b59SJacob Faibussowitsch 
21*0e6b6b59SJacob Faibussowitsch template <typename Derived> // CRTP
22*0e6b6b59SJacob Faibussowitsch class DeviceBase : public util::crtp<Derived, DeviceBase> {
23*0e6b6b59SJacob Faibussowitsch public:
24*0e6b6b59SJacob Faibussowitsch   using derived_type            = Derived;
25*0e6b6b59SJacob Faibussowitsch   using createContextFunction_t = PetscErrorCode (*)(PetscDeviceContext);
26*0e6b6b59SJacob Faibussowitsch 
27*0e6b6b59SJacob Faibussowitsch   // default constructor
28*0e6b6b59SJacob Faibussowitsch   constexpr DeviceBase(createContextFunction_t f) noexcept : create_(f) { }
29*0e6b6b59SJacob Faibussowitsch 
30*0e6b6b59SJacob Faibussowitsch   template <typename T = derived_type>
31*0e6b6b59SJacob Faibussowitsch   PETSC_NODISCARD static constexpr PetscDeviceType PETSC_DEVICE_IMPL() noexcept {
32*0e6b6b59SJacob Faibussowitsch     return T::PETSC_DEVICE_IMPL_();
33*0e6b6b59SJacob Faibussowitsch   }
34*0e6b6b59SJacob Faibussowitsch 
35*0e6b6b59SJacob Faibussowitsch   PETSC_NODISCARD PetscErrorCode        getDevice(PetscDevice, PetscInt) noexcept;
36*0e6b6b59SJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode configureDevice(PetscDevice) noexcept;
37*0e6b6b59SJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode viewDevice(PetscDevice, PetscViewer) noexcept;
38*0e6b6b59SJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode getAttribute(PetscDevice, PetscDeviceAttribute, void *) noexcept;
39*0e6b6b59SJacob Faibussowitsch 
40*0e6b6b59SJacob Faibussowitsch protected:
41*0e6b6b59SJacob Faibussowitsch   // function to create a PetscDeviceContext (the (*create) function pointer usually set
42*0e6b6b59SJacob Faibussowitsch   // via XXXSetType() for other PETSc objects)
43*0e6b6b59SJacob Faibussowitsch   const createContextFunction_t create_;
44*0e6b6b59SJacob Faibussowitsch 
45*0e6b6b59SJacob Faibussowitsch   // if you want the base class to handle the entire options query, has the same arguments as
46*0e6b6b59SJacob Faibussowitsch   // PetscOptionDeviceBasic
47*0e6b6b59SJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode PetscOptionDeviceAll(MPI_Comm, std::pair<PetscDeviceInitType, PetscBool> &, std::pair<PetscInt, PetscBool> &, std::pair<PetscBool, PetscBool> &) noexcept;
48*0e6b6b59SJacob Faibussowitsch 
49*0e6b6b59SJacob Faibussowitsch   // if you want to start and end the options query yourself, but still want all the default
50*0e6b6b59SJacob Faibussowitsch   // options
51*0e6b6b59SJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode PetscOptionDeviceBasic(PetscOptionItems *, std::pair<PetscDeviceInitType, PetscBool> &, std::pair<PetscInt, PetscBool> &, std::pair<PetscBool, PetscBool> &) noexcept;
52*0e6b6b59SJacob Faibussowitsch 
53*0e6b6b59SJacob Faibussowitsch   // option templates to follow, each one has two forms:
54*0e6b6b59SJacob Faibussowitsch   // - A simple form returning only the value and flag. This gives no control over the message,
55*0e6b6b59SJacob Faibussowitsch   //   arguments to the options query or otherwise
56*0e6b6b59SJacob Faibussowitsch   // - A complex form, which allows you to pass most of the options query arguments *EXCEPT*
57*0e6b6b59SJacob Faibussowitsch   //   - The options query function called
58*0e6b6b59SJacob Faibussowitsch   //   - The option string
59*0e6b6b59SJacob Faibussowitsch 
60*0e6b6b59SJacob Faibussowitsch   // option template for initializing the device
61*0e6b6b59SJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode PetscOptionDeviceInitialize(PetscOptionItems *, PetscDeviceInitType *, PetscBool *) noexcept;
62*0e6b6b59SJacob Faibussowitsch   template <typename... T, util::enable_if_t<sizeof...(T) >= 3, int> = 0>
63*0e6b6b59SJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode PetscOptionDeviceInitialize(PetscOptionItems *, T &&...) noexcept;
64*0e6b6b59SJacob Faibussowitsch   // option template for selecting the default device
65*0e6b6b59SJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode PetscOptionDeviceSelect(PetscOptionItems *, PetscInt *, PetscBool *) noexcept;
66*0e6b6b59SJacob Faibussowitsch   template <typename... T, util::enable_if_t<sizeof...(T) >= 3, int> = 0>
67*0e6b6b59SJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode PetscOptionDeviceSelect(PetscOptionItems *, T &&...) noexcept;
68*0e6b6b59SJacob Faibussowitsch   // option templates for viewing a device
69*0e6b6b59SJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode PetscOptionDeviceView(PetscOptionItems *, PetscBool *, PetscBool *) noexcept;
70*0e6b6b59SJacob Faibussowitsch   template <typename... T, util::enable_if_t<sizeof...(T) >= 3, int> = 0>
71*0e6b6b59SJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode PetscOptionDeviceView(PetscOptionItems *, T &&...) noexcept;
72*0e6b6b59SJacob Faibussowitsch 
73*0e6b6b59SJacob Faibussowitsch private:
74*0e6b6b59SJacob Faibussowitsch   // base function for all options templates above, they basically just reformat the arguments,
75*0e6b6b59SJacob Faibussowitsch   // create the option string and pass it off to this function
76*0e6b6b59SJacob Faibussowitsch   template <typename... T, typename F = PetscErrorCode (*)(PetscOptionItems *, const char *, T &&...)>
77*0e6b6b59SJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode PetscOptionDevice(F &&, PetscOptionItems *, const char[], T &&...) noexcept;
78*0e6b6b59SJacob Faibussowitsch 
79*0e6b6b59SJacob Faibussowitsch   // default crtp implementations
80*0e6b6b59SJacob Faibussowitsch   PETSC_NODISCARD static PetscErrorCode init_device_id_(PetscInt *id) noexcept {
81*0e6b6b59SJacob Faibussowitsch     PetscFunctionBegin;
82*0e6b6b59SJacob Faibussowitsch     *id = 0;
83*0e6b6b59SJacob Faibussowitsch     PetscFunctionReturn(0);
84*0e6b6b59SJacob Faibussowitsch   }
85*0e6b6b59SJacob Faibussowitsch 
86*0e6b6b59SJacob Faibussowitsch   PETSC_NODISCARD static constexpr PetscErrorCode configure_device_(PetscDevice) noexcept { return 0; }
87*0e6b6b59SJacob Faibussowitsch   PETSC_NODISCARD static constexpr PetscErrorCode view_device_(PetscDevice, PetscViewer) noexcept { return 0; }
88*0e6b6b59SJacob Faibussowitsch };
89*0e6b6b59SJacob Faibussowitsch 
90*0e6b6b59SJacob Faibussowitsch template <typename D>
91*0e6b6b59SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::getDevice(PetscDevice device, PetscInt id) noexcept {
92*0e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
93*0e6b6b59SJacob Faibussowitsch   PetscCall(this->underlying().init_device_id_(&id));
94*0e6b6b59SJacob Faibussowitsch   device->deviceId           = id;
95*0e6b6b59SJacob Faibussowitsch   device->ops->createcontext = this->underlying().create_;
96*0e6b6b59SJacob Faibussowitsch   device->ops->configure     = this->underlying().configureDevice;
97*0e6b6b59SJacob Faibussowitsch   device->ops->view          = this->underlying().viewDevice;
98*0e6b6b59SJacob Faibussowitsch   device->ops->getattribute  = this->underlying().getAttribute;
99*0e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
100*0e6b6b59SJacob Faibussowitsch }
101*0e6b6b59SJacob Faibussowitsch 
102*0e6b6b59SJacob Faibussowitsch template <typename D>
103*0e6b6b59SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::configureDevice(PetscDevice device) noexcept {
104*0e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
105*0e6b6b59SJacob Faibussowitsch   PetscCall(derived_type::configure_device_(device));
106*0e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
107*0e6b6b59SJacob Faibussowitsch }
108*0e6b6b59SJacob Faibussowitsch 
109*0e6b6b59SJacob Faibussowitsch template <typename D>
110*0e6b6b59SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::viewDevice(PetscDevice device, PetscViewer viewer) noexcept {
111*0e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
112*0e6b6b59SJacob Faibussowitsch   PetscCall(derived_type::view_device_(device, viewer));
113*0e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
114*0e6b6b59SJacob Faibussowitsch }
115*0e6b6b59SJacob Faibussowitsch 
116*0e6b6b59SJacob Faibussowitsch template <typename D>
117*0e6b6b59SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::getAttribute(PetscDevice device, PetscDeviceAttribute attr, void *value) noexcept {
118*0e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
119*0e6b6b59SJacob Faibussowitsch   PetscCall(derived_type::get_attribute_(device->deviceId, attr, value));
120*0e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
121*0e6b6b59SJacob Faibussowitsch }
122*0e6b6b59SJacob Faibussowitsch 
123*0e6b6b59SJacob Faibussowitsch template <typename D>
124*0e6b6b59SJacob Faibussowitsch template <typename... T, typename F>
125*0e6b6b59SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::PetscOptionDevice(F &&OptionsFunction, PetscOptionItems *PetscOptionsObject, const char optstub[], T &&...args) noexcept {
126*0e6b6b59SJacob Faibussowitsch   constexpr auto dtype    = PETSC_DEVICE_IMPL();
127*0e6b6b59SJacob Faibussowitsch   const auto     implname = PetscDeviceTypes[dtype];
128*0e6b6b59SJacob Faibussowitsch   auto           buf      = std::array<char, 128>{};
129*0e6b6b59SJacob Faibussowitsch   constexpr auto buflen   = buf.size() - 1;
130*0e6b6b59SJacob Faibussowitsch 
131*0e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
132*0e6b6b59SJacob Faibussowitsch   if (PetscDefined(USE_DEBUG)) {
133*0e6b6b59SJacob Faibussowitsch     const auto len = std::strlen(optstub) + std::strlen(implname);
134*0e6b6b59SJacob Faibussowitsch 
135*0e6b6b59SJacob Faibussowitsch     PetscCheck(len < buflen, PetscOptionsObject->comm, PETSC_ERR_PLIB, "char buffer is not large enough to hold '%s%s'; have %zu need %zu", optstub, implname, buflen, len);
136*0e6b6b59SJacob Faibussowitsch   }
137*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscSNPrintf(buf.data(), buflen, "%s%s", optstub, implname));
138*0e6b6b59SJacob Faibussowitsch   PetscCall(OptionsFunction(PetscOptionsObject, buf.data(), std::forward<T>(args)...));
139*0e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
140*0e6b6b59SJacob Faibussowitsch }
141*0e6b6b59SJacob Faibussowitsch 
142*0e6b6b59SJacob Faibussowitsch template <typename D>
143*0e6b6b59SJacob Faibussowitsch template <typename... T, util::enable_if_t<sizeof...(T) >= 3, int>>
144*0e6b6b59SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::PetscOptionDeviceInitialize(PetscOptionItems *PetscOptionsObject, T &&...args) noexcept {
145*0e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
146*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscOptionDevice(PetscOptionsEList_Private, PetscOptionsObject, "-device_enable_", std::forward<T>(args)...));
147*0e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
148*0e6b6b59SJacob Faibussowitsch }
149*0e6b6b59SJacob Faibussowitsch 
150*0e6b6b59SJacob Faibussowitsch template <typename D>
151*0e6b6b59SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::PetscOptionDeviceInitialize(PetscOptionItems *PetscOptionsObject, PetscDeviceInitType *inittype, PetscBool *flag) noexcept {
152*0e6b6b59SJacob Faibussowitsch   auto type = static_cast<PetscInt>(util::integral_value(*inittype));
153*0e6b6b59SJacob Faibussowitsch 
154*0e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
155*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscOptionDeviceInitialize(PetscOptionsObject, "How (or whether) to initialize a device", "PetscDeviceInitialize()", PetscDeviceInitTypes, 3, PetscDeviceInitTypes[type], &type, flag));
156*0e6b6b59SJacob Faibussowitsch   *inittype = static_cast<PetscDeviceInitType>(type);
157*0e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
158*0e6b6b59SJacob Faibussowitsch }
159*0e6b6b59SJacob Faibussowitsch 
160*0e6b6b59SJacob Faibussowitsch template <typename D>
161*0e6b6b59SJacob Faibussowitsch template <typename... T, util::enable_if_t<sizeof...(T) >= 3, int>>
162*0e6b6b59SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::PetscOptionDeviceSelect(PetscOptionItems *PetscOptionsObject, T &&...args) noexcept {
163*0e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
164*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscOptionDevice(PetscOptionsInt_Private, PetscOptionsObject, "-device_select_", std::forward<T>(args)...));
165*0e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
166*0e6b6b59SJacob Faibussowitsch }
167*0e6b6b59SJacob Faibussowitsch 
168*0e6b6b59SJacob Faibussowitsch template <typename D>
169*0e6b6b59SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::PetscOptionDeviceSelect(PetscOptionItems *PetscOptionsObject, PetscInt *id, PetscBool *flag) noexcept {
170*0e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
171*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscOptionDeviceSelect(PetscOptionsObject, "Which device to use. Pass " PetscStringize(PETSC_DECIDE) " to have PETSc decide or (given they exist) [0-" PetscStringize(PETSC_DEVICE_MAX_DEVICES) ") for a specific device", "PetscDeviceCreate()", *id, id, flag, PETSC_DECIDE, PETSC_DEVICE_MAX_DEVICES));
172*0e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
173*0e6b6b59SJacob Faibussowitsch }
174*0e6b6b59SJacob Faibussowitsch 
175*0e6b6b59SJacob Faibussowitsch template <typename D>
176*0e6b6b59SJacob Faibussowitsch template <typename... T, util::enable_if_t<sizeof...(T) >= 3, int>>
177*0e6b6b59SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::PetscOptionDeviceView(PetscOptionItems *PetscOptionsObject, T &&...args) noexcept {
178*0e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
179*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscOptionDevice(PetscOptionsBool_Private, PetscOptionsObject, "-device_view_", std::forward<T>(args)...));
180*0e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
181*0e6b6b59SJacob Faibussowitsch }
182*0e6b6b59SJacob Faibussowitsch 
183*0e6b6b59SJacob Faibussowitsch template <typename D>
184*0e6b6b59SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::PetscOptionDeviceView(PetscOptionItems *PetscOptionsObject, PetscBool *view, PetscBool *flag) noexcept {
185*0e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
186*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscOptionDeviceView(PetscOptionsObject, "Display device information and assignments (forces eager initialization)", "PetscDeviceView()", *view, view, flag));
187*0e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
188*0e6b6b59SJacob Faibussowitsch }
189*0e6b6b59SJacob Faibussowitsch 
190*0e6b6b59SJacob Faibussowitsch template <typename D>
191*0e6b6b59SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::PetscOptionDeviceBasic(PetscOptionItems *PetscOptionsObject, std::pair<PetscDeviceInitType, PetscBool> &initType, std::pair<PetscInt, PetscBool> &initId, std::pair<PetscBool, PetscBool> &initView) noexcept {
192*0e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
193*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscOptionDeviceInitialize(PetscOptionsObject, &initType.first, &initType.second));
194*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscOptionDeviceSelect(PetscOptionsObject, &initId.first, &initId.second));
195*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscOptionDeviceView(PetscOptionsObject, &initView.first, &initView.second));
196*0e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
197*0e6b6b59SJacob Faibussowitsch }
198*0e6b6b59SJacob Faibussowitsch 
199*0e6b6b59SJacob Faibussowitsch template <typename D>
200*0e6b6b59SJacob Faibussowitsch inline PetscErrorCode DeviceBase<D>::PetscOptionDeviceAll(MPI_Comm comm, std::pair<PetscDeviceInitType, PetscBool> &initType, std::pair<PetscInt, PetscBool> &initId, std::pair<PetscBool, PetscBool> &initView) noexcept {
201*0e6b6b59SJacob Faibussowitsch   constexpr char optname[] = "PetscDevice %s Options";
202*0e6b6b59SJacob Faibussowitsch   constexpr auto dtype     = PETSC_DEVICE_IMPL();
203*0e6b6b59SJacob Faibussowitsch   const auto     implname  = PetscDeviceTypes[dtype];
204*0e6b6b59SJacob Faibussowitsch   auto           buf       = std::array<char, 128>{};
205*0e6b6b59SJacob Faibussowitsch   constexpr auto buflen    = buf.size() - 1; // -1 to leave room for null
206*0e6b6b59SJacob Faibussowitsch 
207*0e6b6b59SJacob Faibussowitsch   PetscFunctionBegin;
208*0e6b6b59SJacob Faibussowitsch   if (PetscDefined(USE_DEBUG)) {
209*0e6b6b59SJacob Faibussowitsch     // -3 since '%s' is replaced and dont count null char for optname
210*0e6b6b59SJacob Faibussowitsch     const auto len = std::strlen(implname) + PETSC_STATIC_ARRAY_LENGTH(optname) - 3;
211*0e6b6b59SJacob Faibussowitsch 
212*0e6b6b59SJacob Faibussowitsch     PetscCheck(len < buflen, comm, PETSC_ERR_PLIB, "char buffer is not large enough to hold 'PetscDevice %s Options'; have %zu need %zu", implname, buflen, len);
213*0e6b6b59SJacob Faibussowitsch   }
214*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscSNPrintf(buf.data(), buflen, optname, implname));
215*0e6b6b59SJacob Faibussowitsch   PetscOptionsBegin(comm, nullptr, buf.data(), "Sys");
216*0e6b6b59SJacob Faibussowitsch   PetscCall(PetscOptionDeviceBasic(PetscOptionsObject, initType, initId, initView));
217*0e6b6b59SJacob Faibussowitsch   PetscOptionsEnd();
218*0e6b6b59SJacob Faibussowitsch   PetscFunctionReturn(0);
219*0e6b6b59SJacob Faibussowitsch }
220*0e6b6b59SJacob Faibussowitsch 
221*0e6b6b59SJacob Faibussowitsch } // namespace impl
222*0e6b6b59SJacob Faibussowitsch 
223*0e6b6b59SJacob Faibussowitsch } // namespace device
224*0e6b6b59SJacob Faibussowitsch 
225*0e6b6b59SJacob Faibussowitsch } // namespace Petsc
226*0e6b6b59SJacob Faibussowitsch 
227*0e6b6b59SJacob Faibussowitsch #define PETSC_DEVICE_IMPL_BASE_CLASS_HEADER(base_name, T) \
228*0e6b6b59SJacob Faibussowitsch   using base_name = ::Petsc::device::impl::DeviceBase<T>; \
229*0e6b6b59SJacob Faibussowitsch   friend base_name; \
230*0e6b6b59SJacob Faibussowitsch   using base_name::base_name
231*0e6b6b59SJacob Faibussowitsch 
232*0e6b6b59SJacob Faibussowitsch #endif // __cplusplus
233*0e6b6b59SJacob Faibussowitsch 
234*0e6b6b59SJacob Faibussowitsch #endif // IMPLDEVICEBASE_HPP
235