FBasicParticle.hpp 7.8 KB
Newer Older
1
2
3
4
5
6
/**
 * \brief Implementation file of FBasicParticle class
 * \author Quentin Khan
 *
 * \file
 */
Quentin Khan's avatar
Quentin Khan committed
7
8
9
10
11
12

#ifndef FBASIC_PARTICLE_HPP
#define FBASIC_PARTICLE_HPP

#include "Utils/FIntegerSequence.hpp"
#include "Utils/FPoint.hpp"
13
#include "Utils/FTypePack.hpp"
Quentin Khan's avatar
Quentin Khan committed
14

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/**
 * \brief Multi-purpose particle implementation
 *
 * This template implementation of a particle allows simple reuse for several
 * use cases. The aim it to provide an interface that is compatible with the
 * rest of ScalFMM. It is mainly intended to be used as an interface for the
 * particle containers.
 *
 * The Types parameter pack can accept any type that is to be considered as a
 * particle attribute. You can also specify scalfmm::pack type to factorise
 * several types.
 *
 * In the following example, the two specialisations of the class will give the
 * same final structure.
 *
 * ```
 * using FReal = double;
 * static constexpr std::size_t Dim = 3;
 *
 * FBasicParticle<FReal, Dim, int, float, float, float, float>;
 * FBasicParticle<FReal, Dim, int, scalfmm::pack<4, float> >;
 * ```
 *
 * The base of these two classes is
 * ```
 * std::tuple<double, double, double, int, float, float, float, float>;
 * ```
 *
 * \warning Although the classes will have the same final layout, C++ considers
 * these two classes to be different !
 *
 * ##### Example
 *
 * ```
 * // Define a 3D particle with an int attribute
 * using Particle = FBasicParticle<double, 3, int>;
 *
 * Particle p;
 * p.get<>
 * ```
 *
 *
 * \tparam FReal Floating point type
 * \tparam Dim Space dimension count
 * \tparam Types Attributes type list
 *
 */
Quentin Khan's avatar
Quentin Khan committed
62
template<typename _FReal, std::size_t _Dim = 3, typename... Types>
63
class FBasicParticle : public scalfmm::pack_expand_tuple< scalfmm::pack<_Dim, _FReal>, Types... >{
Quentin Khan's avatar
Quentin Khan committed
64
65
66
67
68
69

public:
    /// Storage class : std::tuple<FReal,...(Dim times), Types...>
    using data_t = scalfmm::
        pack_expand_tuple< scalfmm::pack<_Dim, _FReal>, Types... >;

70
    /// Expanded the Types list
Quentin Khan's avatar
Quentin Khan committed
71
72
73
    using types_tuple_t = scalfmm::
        pack_expand_tuple< Types... >;

74
75
76
77
78
79
80
81
82
83
84
85
    /// Expand std::enable_if if possible
    template<bool value>
    using sfinae_check = typename std::enable_if<value, bool>::type;

    /**
     * \brief Check parameter pack size vs. attribute + dimension count at
     * compile time
     *
     * \return true if the parameter pack is shorter than the attribute list
     * size + the dimension
     */
    template<typename... Ts>
86
    constexpr static bool correct_attribute_list_size() {
87
88
89
        return std::tuple_size<data_t>::value >= sizeof...(Ts) + Dim;
    }

Quentin Khan's avatar
Quentin Khan committed
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
    /// Space dimensions
    constexpr static std::size_t Dim = _Dim;
    /// Size of #data_t tuple
    constexpr static std::size_t NbAttributes = std::tuple_size<data_t>::value - Dim;

    /// Floating point type
    using FReal = _FReal;
    /// #data_t alias, required by the FVariadicParticleContainer
    using attribute_tuple_t = data_t;
    /// Position type, required by the FVariadicParticleContainer
    using position_t = FPoint<FReal, Dim>;

    /// Default constructor
    FBasicParticle() = default;
    /// Default copy constructor
    FBasicParticle(const FBasicParticle&) = default;
    /// Default copy operator
    FBasicParticle& operator=(const FBasicParticle&) = default;
    /// Default move constructor
    FBasicParticle(FBasicParticle&&) = default;
    /// Default move operator
    FBasicParticle& operator=(FBasicParticle&&) = default;

113
114
115
    /**
     * \brief Constructor from position and types
     *
Quentin Khan's avatar
Quentin Khan committed
116
117
     * \tparam Ts Attributes parameter pack; if Ts is too long, this will not
     * compile.
118
119
120
121
122
123
124
125
     *
     * \param pos Particle position
     * \param ts Attributes
     *
     * \warning There may be less attributes than defined by the particle, in
     * that case the missing ones are zero constructed.
     */
    template<typename... Ts,
126
             sfinae_check<correct_attribute_list_size<Ts...>()> = 0>
Quentin Khan's avatar
Quentin Khan committed
127
    FBasicParticle(const position_t& pos, Ts&&... ts) :
128
129
130
131
132
        FBasicParticle(std::make_index_sequence<Dim>(),
                       std::make_index_sequence<std::tuple_size<data_t>::value-sizeof...(ts)-Dim>(),
                       pos,
                       std::forward<Ts>(ts)...
            )
Quentin Khan's avatar
Quentin Khan committed
133
134
135
136
137
    {}

    /// Constructor from tuple equivalent to #data_t
    template<typename... Ts>
    FBasicParticle(const std::tuple<Ts...>& ts) :
138
        data_t(ts)
Quentin Khan's avatar
Quentin Khan committed
139
140
    {}

141
142
    /**
     * \brief Position getter
Quentin Khan's avatar
Quentin Khan committed
143
144
145
146
147
148
149
150
151
152
153
154
155
156
     *
     * The position is stored in the #_data tuple, to extract it we need to
     * recreate a position_t object. This is done by the position_impl() method.
     *
     * \return A new position_t object
     */
    position_t position() const {
        return position_impl(std::make_index_sequence<Dim>());
    }

    void setPosition(const position_t& pos) {
        return setPosition_impl(pos, std::make_index_sequence<Dim>());
    }

157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
    /**
     * \brief Get a reference to the Ith attribute
     *
     * \tparam I Index of the attribute to get
     */
    template<std::size_t I>
    auto attribute() -> decltype(std::get<Dim+I>(*this)) {
        return std::get<Dim+I>(*this);
    }

    /**
     * \brief Get a const reference to the Ith attribute
     *
     * \tparam I Index of the attribute to get
     */
    template<std::size_t I>
    auto attribute() const -> decltype(std::get<Dim+I>(*this)) {
        return std::get<Dim+I>(*this);
    }

177
178
179
180

    /**
     * \brief Get a tuple filled with copies of the attributes
     */
Quentin Khan's avatar
Quentin Khan committed
181
182
    types_tuple_t attributes() const {
        return attributes_impl(
183
            std::make_index_sequence<std::tuple_size<types_tuple_t>::value>());
Quentin Khan's avatar
Quentin Khan committed
184
185
    }

186
187
188
    /**
     * \brief Convert particle to a tuple
     */
Quentin Khan's avatar
Quentin Khan committed
189
    data_t& data() {
190
        return *this;
Quentin Khan's avatar
Quentin Khan committed
191
192
    }

193
194
195
    /**
     * \brief Convert particle to a tuple
     */
Quentin Khan's avatar
Quentin Khan committed
196
    const data_t& data() const {
197
        return *this;
Quentin Khan's avatar
Quentin Khan committed
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
    }

    template<std::size_t I>
    auto get() -> decltype(std::get<I>(this->data())) {
        return std::get<I>(this->data());
    }

    template<std::size_t I>
    auto get() const -> decltype(std::get<I>(this->data())) {
        return std::get<I>(this->data());
    }

    friend bool operator==(const FBasicParticle& lhs, const FBasicParticle& rhs) {
        return lhs.data() == rhs.data();
    }

private:
215
216
217
218
219
    /**
     * \brief Contructor implementation
     *
     * Builds the particle, zero constructing missing arguuments.
     */
220
221
222
223
224
    template<typename... Ts, std::size_t... Is, std::size_t... Js>
    FBasicParticle(std::index_sequence<Is...>, std::index_sequence<Js...>,
                   const FPoint<FReal, Dim>& pos, Ts&&... ts) :
        data_t(pos[Is]..., std::forward<Ts>(ts)...,
               typename std::tuple_element<Dim+Js+sizeof...(ts), data_t>::type(0)...)
Quentin Khan's avatar
Quentin Khan committed
225
    {
226
        //static_assert(sizeof...(Ts) == NbAttributes, "Parameter count is incorrect");
Quentin Khan's avatar
Quentin Khan committed
227
    }
Quentin Khan's avatar
Quentin Khan committed
228

229
230
231
232
233
234
    /**
     * \brief #position method implementation
     *
     * \tparam Is Index sequence of the position elements in the tuple, deduced
     * using arguments
     */
Quentin Khan's avatar
Quentin Khan committed
235
236
    template<std::size_t... Is>
    position_t position_impl(std::index_sequence<Is...>) const{
237
        return position_t(std::get<Is>(this->data())...);
Quentin Khan's avatar
Quentin Khan committed
238
239
    }

240
241
242
243
244
245
246
247
    /**
     * \brief #setPosition method implementation
     *
     * \tparam Is Index sequence of the position elements in the tuple, deduced
     * using arguments
     *
     * \param pos new position
     */
Quentin Khan's avatar
Quentin Khan committed
248
    template<std::size_t... Is>
249
250
    void setPosition_impl(const position_t& pos, std::index_sequence<Is...>) {
        auto l = {std::get<Is>(this->data()) = pos[Is] ...};
Quentin Khan's avatar
Quentin Khan committed
251
252
253
254
        (void)l;
    }


255
256
257
258
259
260
261
262
    /**
     * \brief #attributes method implementation
     *
     * \tparam Is Index sequence of the attributes in the tuple, deduced using
     * arguments
     *
     * \param pos new position
     */
263
264
265
    template<std::size_t... Is>
    types_tuple_t attributes_impl(std::index_sequence<Is...>) const {
        return types_tuple_t(std::get<Is+Dim>(*this)...);
Quentin Khan's avatar
Quentin Khan committed
266
267
268
269
270
271
    }

};


#endif /* FBASIC_PARTICLE_HPP */