Salut je tourne autour de 20 FPS oui à mon avis il y a trop de polygones qui s'affichent.
Salut je tourne autour de 20 FPS oui à mon avis il y a trop de polygones qui s'affichent.
Salut, j'ai trouvé le problème pour les ombres qui ne s'affichaient pas correctement, mais, difficile d'avoir quelque chose de parfait parce que le zNear varie suivant la pente et il faut calculer le bonne angle pour incliner l'ombre en fonction de la pente. (Car sinon l'ombre ne s'affiche pas car elle est en dessous de la pente) Bref c'est difficile d'avoir quelque chose de très précis.
salut 20 fps ? Ah oui ça rame.
Est-ce que vous avez une machine puissante ?
Salut! J'ai un intel i5 6 coeurs avec 16GB de RAM et une CG nvidia gforce 1660 super avec 6GB de VRAM. J'ai acheté mon PC il y a 2-3 ans environ. Je ne comprends pas pourquoi le FPS est si bas surtout avec un geometryShader je pensais que ça multiplierait le temps par 6 étant donné que je ne dessine qu'une seule fois la scène au lieu de 6 fois mais on dirait que le CPU attend après le GPU car malgré que j'appelle glDraw une seule fois au lieu de 6 ça ne soulage pas le CPU et au niveau du GPU le nombre de polygones à dessiner reste le même normalement.

Non mais je suis désolé 20fps pour la scène que tu affiches on est en 2024 pas 1990.
Le problème c'est que tu ne sais pas coder un moteur de jeux.
C'est pas un mal en soit ce n'est pas donné à tout le monde, enfin là juste afficher une skybox et un terrain avec une ombre mdr quoi.
Là c'est vraiment un problème structurel.
Oui enfin ça ne rame pas donc je ne sais pas si mon compteur de FPS est bon enfin soit c'est surtout quand je met ensemble le rendu des ombres, des lumières et de la réfraction que ça consomme du FPS. Je pense que le soucis est le fait que je dessine la scène trop de fois. J'utilise pas mal de textures de rendu pour gérer la transparence. Donc même si je n'ai pas énormément de polys, ça bouffe du FPS.
@laurent : et avec des jeux commerciaux vous obtenez un mauvais framerate aussi ?
Avez-vous été voir dans le panneau de configuration de n-vidia ?
Salut. Je dois voir cela mais avant assassin's Creed Odyssée tournait à 60 de FPS sur mon pc avec les graphismes au max... Il y a sûrement quelque chose que j'ai mal fait... pourtant je n'effectue qu'un seul appel à draw par shader j'ai essayé de réduire le plus possible les appels à draw avec le bindless texturing l'indirect rendering et le batching. Il n'y a que lorsque je change de shader ou de type de primitive que je rappelle le draw. Même si je dessine dans 10 framebuffers la même scène je pensais pas que ça boufferait autant le FPS.
Pour les performances, la vérité se trouve dans les profileurs, ou tout outil qui remonte des données factuels sur le temps pris par telle ou telle fonctionnalité. D'ailleurs, on ne ferait pas d'optimisation sans ces données.
Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi
Ma page sur DVP
Mon Portfolio
Qui connaît l'erreur, connaît la solution.
Ok mais quand je compile sur code::blocks avec l'option -pg je n'ai pas de données en sorties du profiler sinon oui j'avais pensé à l'utiliser.
Je viens de corriger un bug concernant la classe qui récupère toutes les informations sur une classe, j'ai dû trouver un moyen de supprimer tout ce qu'il y avait entre les crochets si il y a du code dans le fichier.hpp ça n'était pas si simple étant donné que dans les crochets des fonctions il pouvait y avoir d'autres crochets pour des if, while, etc...
Après une fois cela de fait c'est facile de récupérer le nom de la fonction et les arguments.
Bonjour, je n'arrive pas à faire fonctionner gprof sous code::blocks ça va être un dur de savoir quelle fonction ralenti l'exécution du code. Mais le problème vient sûrement de mes fonctions de dessin.
Pourtant je ne fait que d'ajouter tout mes sommets dans un VBO avant d'appeler la fonction draw pour tout dessiner en une fois. (Il n'y a que lorsque j'ai des types de primitives ou des shaders différents que je fais plusieurs draws)
Mais j'utilise pas mal de FBO, maintenant toutes ne dessinent pas forcément tout la scène ça dépend de ce que je passe comme type d'entités à mon composant et si c'est une lumière ou un objet rétractable, etc...
Mais la chute du FPS provient de mes fonctions de dessins et je ne comprend comment le simple fait d'ajouter des sommets dans un VBO peut faire chuter ainsi le FPS...
Mais bon il y a deux types de primitives ici, un type pour le terrain des Quads et un pour le modèle 3D des triangles...
EDIT : Sinon je recherche un programmeur qui s'y connait bien en programmation graphique pour améliorer les performances, résoudre ces problèmes de glitchs et finir l'implémentation VULKAN.
gprof fonctionne et apparemment c'est les push_back qui font descendre le FPS.
Cool. Y a sûrement moyen d'éviter quelques copies
De plus, de mémoire, un VBO, ça se prépare une fois, pas besoin de copier les données à chaque image, non ?
Quel en serait l'intérêt (autrement dit, quelle est la carotte) ?EDIT : Sinon je recherche un programmeur qui s'y connait bien en programmation graphique pour améliorer les performances, résoudre ces problèmes de glitchs et finir l'implémentation VULKAN.
Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi
Ma page sur DVP
Mon Portfolio
Qui connaît l'erreur, connaît la solution.
Salut! Ca dépend ce qu'il me demande faut voir lol.
Non mais finalement tout seul je m'en sors plutôt bien, j'arrive à corriger des bugs d'affichage (des glitch), maintenant le problème ça reste l'optimisation au niveau du CPU.
Mais je préfère le faire seul finalement la programmation ça me permet de mieux apprendre comment fonctionne la programmation graphique.
J'ai enfin pu régler le problème de scintillement des pixels de l'ombre lorsque il y avait quelque chose entre la caméra et l'ombre c'était juste un problème de synchronisation : plusieurs shaders pour le même pixel s'exécutaient en même temps du coup ce qui était lu par un shader n'était pas ce qui avait été écrit précédemment par un autre shader pour un même pixel, je pensais que memoryBarrier et coherent résoudrait le problème mais en fait non il fallait utiliser l'extension interlock arb pour empêcher qu'une autre invocation de shader pour le même pixel lise la valeur de z pendant que une autre invocation de shader pour ce même pixel l'écrive.
Bref un peu difficile à comprendre encore pour moi la synchronisation au niveau du GPU et de ce que fait exactement memoryBarrier et coherent mais ça ne faisait pas ce à quoi je m'attendais...
Salut! La chute du FPS provient du resize et de la copie de mes sommets dans le vertex buffer avant le dessin. (Surtout dans le renderer qui dessine la réfraction et la réflexion) Je pense que pour optimiser je dois faire des vbos pour les objets statique (terrains, modèles 3D statiques, etc...) que je ne remet à jour que au début du programme et des vbos pour les objets dynamiques (animations, particules, etc...) que je remet à jour à chaque frame. Et pour les objets statique ne passer que les indices des objets qui sont visible.
Salut! Par faute de FPS bas je vais faire une pause sur le développement de la 3D, je reprendrais ça plus tard car là, je n'ai pas d'idées pour comment optimiser cela.
Du coup j'ai repris le développement de l'éditeur (en 2D) et j'ai corriger des bugs avec le plugin de génération de scripts, désormais on peut créer des quêtes par exemple et les ajouter aux pnj grâce à des scripts créé soi même. Une fonctionnalité que je n'ai pas trouvé dans UE et Unity pour ça que je fais mon propre moteur. Je dois encore optimiser mon "runtime compiler" pour ne pas recompiler le code qui ne change pas.
Salut! J'ai trouvé une idée pour optimiser le moteur, en fait, j'utilise mal les VBO. Je vais ne les remplir que si on ajoute ou supprime des entités mais plus pendant le rendu. Pour les entités dynamique (animations, particules) je vais modifier les sommets dans la VBO à la position de l'entité dans le VBO en m'arrangeant pour avoir des tableaux de sommets à taille fixe. Et je vais à chaque rendu ne mettre à jour que les indices de mes vbo pour ne dessiner que ce qui est visible. Je n'ai pas encore tester je suis seulement entrain de modifier le code mais ça devrait améliorer grandement les perfs.
Et faire un draw call par mesh ? Je pense pas que ça soit très opti.
J'ai essayé de faire un VBO avec toutes les entités de la scène et stocker la position de l'entité dans le VBO et ne mettre à jour que des indexes à chaque frame mais ça ne fonctionne pas. :/
Salut! J'ai corrigé une erreur de compilation dans le fichier fastDelegate.h
Désormais, ce code-ci :
Compile, plus obligé d'utiliser un pointeur sur l'objet pour le pointeur de fonction membre.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2SkillAction skillAction; skill.setSkillBehaviour(new FastDelegate<void>(&SkillAction::launchLastHeal, skillAction, static_cast<Hero*>(hero), skill));
C'était un membre de ce forum qui m'avait proposé ce code que j'ai amélioré. J'ai également supprimé la macro déguelasse avec les void* pour les placeholder et j'ai utilisé du code c++17.
Ce qui donne :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240 #ifndef ODFAEG_TMP_HPP #define ODFAEG_TMP_HPP #include <tuple> namespace odfaeg { namespace core { template < typename Tp, typename... List > struct contains : std::true_type {}; template < typename Tp, typename Head, typename... Rest > struct contains<Tp, Head, Rest...> : std::conditional< std::is_same<Tp, Head>::value, std::true_type, contains<Tp, Rest...> >::type {}; template <typename T, typename Tuple> struct has_type; template <typename T> struct has_type<T, std::tuple<>> : std::false_type {}; template <typename T, typename U, typename... Ts> struct has_type<T, std::tuple<U, Ts...>> : has_type<T, std::tuple<Ts...>> {}; template <typename T, typename... Ts> struct has_type<T, std::tuple<T, Ts...>> : std::true_type {}; template < typename Tp > struct contains<Tp> : std::false_type {}; template <typename T, typename U=void, typename... Types> constexpr std::size_t index() { return std::is_same<T, U>::value ? 0 : 1 + index<T, Types...>(); } //Make index sequences from an offset. template<std::size_t N, typename Seq> struct offset_sequence; template<std::size_t N, std::size_t... Ints> struct offset_sequence<N, std::index_sequence<Ints...>> { using type = std::index_sequence<Ints + N...>; }; template<std::size_t N, typename Seq> using offset_sequence_t = typename offset_sequence<N, Seq>::type; //Concatenate two sequences of indexes into one. template<typename Seq1, typename Seq> struct cat_sequence; template<std::size_t... Ints1, std::size_t... Ints2> struct cat_sequence<std::index_sequence<Ints1...>, std::index_sequence<Ints2...>> { using type = std::index_sequence<Ints1..., Ints2...>; }; template<typename Seq1, typename Seq2> using cat_sequence_t = typename cat_sequence<Seq1, Seq2>::type; template<typename T, typename Seq> struct select_tuple; template<typename T, std::size_t... Ints> //Return a tuple with elements at indexes. struct select_tuple<T, std::index_sequence<Ints...>> { using type = std::tuple<std::tuple_element_t<Ints, T>...>; }; //Remove the Nth elements of a tuple. template<std::size_t N, typename T> struct remove_Nth { static constexpr auto size = std::tuple_size_v<T>; using first = std::make_index_sequence<N>; using rest = offset_sequence_t<N+1, std::make_index_sequence<size-N-1>>; using indices = cat_sequence_t<first, rest>; using type = typename select_tuple<T, indices>::type; }; namespace meta { template <std::size_t I, class T, bool B> struct get; template <std::size_t I, class T> struct get <I, T, true> { using type = T; }; template <std::size_t I, class T> struct get <I, T, false> { using type = typename remove_Nth<I, T>::type; }; template <template<class...> class Pred, class T, bool B, std::size_t NB, class Seq> struct append_if {}; template <template<class...> class Pred, class T, std::size_t NB, std::size_t IH, std::size_t... IT> struct append_if<Pred, T, true, NB, std::index_sequence<IH, IT...>> { using f = typename append_if<Pred, typename get<IH-NB, T, Pred<std::tuple_element_t<IH-NB, T>>::value>::type, Pred<std::tuple_element_t<IH-NB, T>>::value, NB, std::index_sequence<IT...>>::f; }; template <template<class...> class Pred, class T, std::size_t NB, std::size_t IH, std::size_t... IT> struct append_if<Pred, T, false, NB, std::index_sequence<IH, IT...>> { using f = typename append_if<Pred, typename get<IH-NB, T, Pred<std::tuple_element_t<IH-NB, T>>::value>::type, Pred<std::tuple_element_t<IH-NB, T>>::value, NB+1, std::index_sequence<IT...>>::f; }; template <template<class...> class Pred, class T, std::size_t NB, std::size_t IH> struct append_if<Pred, T, true, NB, std::index_sequence<IH>> { using f = typename get<IH-NB, T, Pred<std::tuple_element_t<IH-NB, T>>::value>::type; }; template <template<class...> class Pred, class T, std::size_t NB, std::size_t IH> struct append_if<Pred, T, false, NB, std::index_sequence<IH>> { using f = typename get<IH-NB, T, Pred<std::tuple_element_t<IH-NB, T>>::value>::type; }; template<template <class...> class Pred, typename T> struct copy_if { using f = typename append_if<Pred, T, Pred<std::tuple_element_t<0, T>>::value, 0, std::make_index_sequence<std::tuple_size<T>::value>>::f; }; template<template <class...> class Pred> struct copy_if <Pred, std::tuple<>> { using f = std::tuple<>; }; template <std::size_t NB, typename T, bool B, std::size_t IH, std::size_t IH2, std::size_t N> struct remove_if_sames { }; template <std::size_t NB, typename T, std::size_t IH1, std::size_t IH2, std::size_t N> struct remove_if_sames<NB, T, true, IH1, IH2, N> { using f = typename remove_if_sames<NB, typename get<IH2-NB, T, !std::is_same<std::tuple_element_t<IH1, T>, std::tuple_element_t<IH2-NB, T>>::value>::type, !std::is_same<std::tuple_element_t<IH1, T>, std::tuple_element_t<IH2-NB, T>>::value, IH1, IH2+1, N>::f; }; template <std::size_t NB, typename T, std::size_t IH1, std::size_t IH2, std::size_t N> struct remove_if_sames<NB, T, false, IH1, IH2, N> { using f = typename remove_if_sames<NB+1, typename get<IH2-NB, T, !std::is_same<std::tuple_element_t<IH1, T>, std::tuple_element_t<IH2-NB, T>>::value>::type, !std::is_same<std::tuple_element_t<IH1, T>, std::tuple_element_t<IH2-NB, T>>::value, IH1, IH2+1, N>::f; }; template <std::size_t NB, typename T, std::size_t IH1, std::size_t N> struct remove_if_sames<NB, T, true, IH1, N, N> { using f = typename get<N-NB, T, !std::is_same<std::tuple_element_t<IH1, T>, std::tuple_element_t<N-NB, T>>::value>::type; }; template <std::size_t NB, typename T, std::size_t IH1, std::size_t N> struct remove_if_sames<NB, T, false, IH1, N, N> { using f = typename get<N-NB-1, T, !std::is_same<std::tuple_element_t<IH1, T>, std::tuple_element_t<N-NB-1, T>>::value>::type; }; template <typename T, std::size_t IH, bool B, bool B2> struct make_unique { using f = typename make_unique<typename remove_if_sames<0, T, true, IH, IH+1, std::tuple_size<T>::value-1>::f, IH+1, IH == std::tuple_size<T>::value - 2, (std::tuple_size<T>::value > 1)>::f; }; template <typename T, std::size_t IH> struct make_unique<T, IH, false, true> { using f = typename make_unique<typename remove_if_sames<0, T, true, IH, IH+1, std::tuple_size<T>::value-1>::f, IH+1, IH == std::tuple_size<T>::value - 2, (std::tuple_size<T>::value > 1)>::f; }; template <typename T, std::size_t IH> struct make_unique<T, IH, true, true> { using f = typename remove_if_sames<0, T, true, IH-1, IH, std::tuple_size<T>::value-1>::f; }; template <typename T, std::size_t IH> struct make_unique<T, IH, false, false> { using f = T; }; template <typename T> struct unique { using f = typename make_unique<T, 0, false, (std::tuple_size<T>::value > 1)>::f; }; template <> struct unique <std::tuple<>> { using f = std::tuple<>; }; template <std::size_t I, std::size_t J, class T, bool B> struct swap_if { }; template <std::size_t I, std::size_t J, class T> struct swap_if<I, J, T, true> { using first = std::make_index_sequence<I>; using second = std::index_sequence<J>; using third = offset_sequence_t<I+1,std::make_index_sequence<J-I-1>>; using four = std::index_sequence<I>; using last = offset_sequence_t<J+1,std::make_index_sequence<std::tuple_size<T>()-J-1>>; using indices = cat_sequence_t<first, cat_sequence_t<second, cat_sequence_t<third, cat_sequence_t<four, last>>>>; using type = typename select_tuple<T, indices>::type; }; template <std::size_t I, std::size_t J, class T> struct swap_if<I, J, T, false> { using type = T; }; template <class Comp, typename T, std::size_t IH1, std::size_t IH2, std::size_t N> struct swap_elements { using f = typename swap_elements<Comp, typename swap_if<IH1, IH2, T, !Comp::template f<std::tuple_element_t<IH1, T>, std::tuple_element_t<IH2, T>>::value>::type, IH1, IH2+1, N>::f; }; template <class Comp, typename T, std::size_t IH1, std::size_t N> struct swap_elements<Comp, T, IH1, N, N> { using f = typename swap_if<IH1, N, T, !Comp::template f<std::tuple_element_t<IH1, T>, std::tuple_element_t<N, T>>::value>::type; }; template <typename Comp, typename T, std::size_t IH, bool B, bool B2> struct sort_impl { }; template <typename Comp, typename T, std::size_t IH> struct sort_impl<Comp, T, IH, false, true> { using f = typename sort_impl<Comp, typename swap_elements<Comp, T, IH, IH+1, std::tuple_size<T>::value-1>::f, IH + 1, IH == std::tuple_size<T>::value-2, (std::tuple_size<T>::value > 1)>::f; }; template <typename Comp, typename T, std::size_t IH> struct sort_impl<Comp, T, IH, true, true> { using f = typename swap_elements<Comp, T, IH-1, IH, std::tuple_size<T>::value-1>::f; }; template <typename Comp, typename T, std::size_t IH> struct sort_impl<Comp, T, IH, false, false> { using f = T; }; template <typename Comp, typename T> struct sort { using f = typename sort_impl<Comp, T, 0, false, (std::tuple_size<T>::value > 1)>::f; }; template <typename Comp> struct sort <Comp, std::tuple<>> { using f = std::tuple<>; }; template <class T, template<class...> class R, class Seq> struct lift { }; template <class T, template<class...> class R, std::size_t... Ints> struct lift <T, R, std::index_sequence<Ints...>> { using f = R<std::tuple_element_t<Ints, T>...>; }; } //Return a tuple with elements at indexes. template <typename T, std::size_t... Ints> auto select_tuple_vals(T& tuple, std::index_sequence<Ints...>) { return std::make_tuple(std::get<Ints>(tuple)...); } //Remove the Nth elements of a tuple. template<std::size_t N, typename T> auto remove_Nth_vals(T& tuple) { constexpr auto size = tuple.nbTypes(); using first = std::make_index_sequence<N>; using rest = offset_sequence_t<N+1, std::make_index_sequence<size-N-1>>; using indices = cat_sequence_t<first, rest>; return select_tuple(tuple, indices{}); } } } #endif
Au lieu du code déguelasse qu'on m'avait proposé et que l'on m'avait dit qu'il n'y avait pas d'autre façon de faire :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830 namespace odfaeg { namespace core { #ifndef VOIDPTR_DELEGATE_IMPL /** * \file fastDelegate.h * \class Parameter * \brief Hold value for a placeholder. * \param i : the placeholder's position. * \param T : the placeholder's type. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<std::size_t i, class T> struct Parameter { T value; }; /** * \file fastDelegate.h * \class LateParameters * \brief Wrap each placeholders's values using inheritance and variadic template. * \param Placeholders : the placeholders. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class... Placeholders> struct LateParameters : Parameter<Placeholders::index, typename Placeholders::type>... { }; /** * \file fastDelegate.h * \class IRefVal * \brief Interface for the warppers to references, values and pointers. * This class is used store references, pointers and values to pass to the callack's functions. * \param T : the type of the value to wrap. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class T, class LateParamsT, bool isCopiable> struct IRefVal { /**\fn * \brief default constructor */ IRefVal()=default; /**\fn T& get() * \brief get the reference of the wrapped type. * \return the reference of the wrapped type. */ virtual T& bind(void* params) = 0; virtual T& get() = 0; /**\fn std::unique_ptr<IRefVal<T>> clone() const = 0; * \brief copy the wrapper. * \return the copied wrapper.*/ virtual std::unique_ptr<IRefVal<T, LateParamsT, isCopiable>> clone() const = 0; /**\fn destructor*/ virtual ~IRefVal(){} protected: /**\fn IRefVal(const IRefVal&) * \brief constructor, pass the reference to wrap. * \param const IRefVal& : the reference to wrap. */ IRefVal(const IRefVal&){} /** \fn IRefVal& operator=(const IRefVal&) * \brief affector. * \param const IRefVal& : the wrapper to affect. * \return the affected wrapper.*/ IRefVal& operator=(const IRefVal&) { return *this; } }; /** * \file fastDelegate.h * \class Ref * \brief Warp a reference. (Use std::reference_wrapper so we can pass a reference with std::ref) * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template <typename T, typename LateParamsT, bool isCopiable> class RefVal; template<class T, typename LateParamsT, bool isCopiable> struct Ref : IRefVal<T, LateParamsT, isCopiable> { /** *\fn Ref(const std::reference_wrapper<T>& r) *\brief Constructor : pass an std::reference_wrapper to the wrapper. *\param std::reference_wrapper<T>& r : the reference_wrapper. */ Ref(const std::reference_wrapper<T>& r) : ref(r) {} /** * \fn T& bind() * \brief return a reference to an object. * \param void* address of the wrapper to placeholder's values. * \return T& the reference to the object. */ T& bind(void* params) { return ref.get(); } /** * \fn T& get() * \brief return a reference to an object. * \return T& the reference to the object. */ T& get() { return ref.get(); } /** * \fn std::unique_ptr<IRefVal<T>> clone() const * \brief copy the reference wrapper. * \return std::unique_ptr<IRefVal<T>> : the cloned wrapper. */ std::unique_ptr<IRefVal<T, LateParamsT, isCopiable>> clone() const { return std::make_unique<Ref>(*this); } private: std::reference_wrapper<T> ref; /**> the std::reference_wrapper which warp the reference.*/ }; /** * \file fastDelegate.h * \class Val * \brief Warp a value. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class T, class LateParamsT, bool isCopiable> struct Val : IRefVal<T, LateParamsT, isCopiable> { }; template<class T, class LateParamsT> struct Val<T, LateParamsT, true> : IRefVal<T, LateParamsT, true> { /**\fn Val(const T& t) * \brief pass a value to the wrapper. * \param const T& t : the value to pass. */ Val(const T& t) : val(t) {} /** * \fn T& bind() * \brief return a the value. * \param void* address of the wrapper to placeholder's values. * \return T& the value. */ T& bind(void* params) { return val; } /** \fn * \brief return the value * \return T& : return the value. */ //template<class = typename std::enable_if_t<std::is_copy_constructible_v<T>>> T& get() { return val; } /*template<class...D, class = typename std::enable_if_t<!std::is_copy_constructible_v<T>>> T& get() { return std::move(val); }*/ /** * \fn std::unique_ptr<IRefVal<T>> clone() const * \brief copy the value wrapper. * \return std::unique_ptr<IRefVal<T>> : the cloned wrapper. */ std::unique_ptr<IRefVal<T, LateParamsT, true>> clone() const { return std::make_unique<Val>(*this); } private: T val; /**> T val : keep the value of the wrapper.*/ }; template<class T, class LateParamsT> struct Val<T, LateParamsT, false> : IRefVal<T, LateParamsT, false> { /**\fn Val(const T& t) * \brief pass a value to the wrapper. * \param const T& t : the value to pass. */ Val(const T& t) : val(t) {} /** * \fn T& bind() * \brief return a the value. * \param void* address of the wrapper to placeholder's values. * \return T& the value. */ T& bind(void* params) { return val; } /** \fn * \brief return the value * \return T& : return the value. */ //template<class = typename std::enable_if_t<std::is_copy_constructible_v<T>>> T& get() { return std::move(val); } /*template<class...D, class = typename std::enable_if_t<!std::is_copy_constructible_v<T>>> T& get() { return std::move(val); }*/ /** * \fn std::unique_ptr<IRefVal<T>> clone() const * \brief copy the value wrapper. * \return std::unique_ptr<IRefVal<T>> : the cloned wrapper. */ std::unique_ptr<IRefVal<T, LateParamsT, false>> clone() const { return std::make_unique<Val>(*this); } private: T val; /**> T val : keep the value of the wrapper.*/ }; /** * \file fastDelegate.h * \class ph * \brief user defined placeholders. * \param I placeholder's position. * \param T placeholder's type. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<size_t I, class T> struct ph { using type = T; /**> alias to the type.*/ static constexpr std::size_t index = I; /** > alias to the position.*/ }; /** * \file fastDelegate.h * \class is_placeholder * \brief trait class if the type is not a placeholder the compiler choose this class's version. * \param T the type. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class T> struct is_placeholder : std::false_type {}; /** * \file fastDelegate.h * \class is_placeholder * \brief trait class specialization if the type is a placeholder the compiler choose this class's version. * \param T the type. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<std::size_t I, class T> struct is_placeholder<ph<I, T>> : std::true_type {}; /** * \file fastDelegate.h * \class LessPlaceceholder * \brief class used to sort placeholder's from the first position to the last type's position. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ struct LessPlaceceholder { template<class PlaceHolder1, class PlaceHolder2> using f = std::bool_constant<PlaceHolder1::index < PlaceHolder2::index>; /**> if the first placeholder position is smaller than the second placeholder's position.*/ }; /** * \file fastDelegate.h * \class placeholder * \brief Warp a placeholder. * \param I : the placeholder's position. * \param T : the placeholder's type. * \param LateParamsT : the type of the placeholders holder. (we need to pass it for the cast!) * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<size_t I, class T, class LateParamsT, bool isCopiable> struct placeholder : IRefVal<T, LateParamsT, isCopiable> { /** * \fn std::unique_ptr<IRefVal<T, LateParamsT>> clone() const * \brief copy the placeholder wrapper. * \return std::unique_ptr<IRefVal<T, LateParamsT>> : the cloned wrapper. */ std::unique_ptr<IRefVal<T, LateParamsT, isCopiable>> clone() const { return std::make_unique<placeholder>(*this); } /** * \fn T& bind(void* params) * \brief extract the placeholder's value from the placeholers's holder. * \param void* address of the wrapper to placeholder's values. * \return T& the value. */ T& bind(void* params) { //We cast from void* to the placeholders's holder type. LateParamsT& paramsT = *static_cast<LateParamsT*>(params); //We cast from base type to the derived type to extract the placeholder's value. return static_cast<Parameter<I, T>&>(paramsT).value; } /** \fn T& get() * \brief we don't need to return anything, this function is never called anyway. * \return T& : return's nothing. */ T& get() { } }; /** * \file fastDelegate.h * \class RefVal * \brief Wrap a pointer, a value or a reference and keep a pointer to the generic wrapper. * Call the right constructor depending on the wrapper's or value's type. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class T, class LateParamsT, bool isCopiable> struct RefVal { /** * \fn RefVal (const T& t) * \brief constructor : construct a wrapper to a value * \param const T& t : the value to */ RefVal(const T& t) : rv(std::make_unique<Val<T, LateParamsT, isCopiable>>(t)) {} /** * \fn RefVal (const std::reference_wrapper<T>& r) * \brief constructor : construct a wrapper to an std::reference_wrapper. * \param const std::reference_wrapper<T>& : the std::reference_wrapper to pass. */ RefVal(const std::reference_wrapper<T>& r) : rv(std::make_unique<Ref<T, LateParamsT, isCopiable>>(r)) {} /** * \fn RefVal (ph<I,T>&&) * \brief constructor : construct a wrapper to a placeholder from a user defined placeholder. * \param ph<I,T>&& the placeholder. */ template<size_t I> RefVal(ph<I,T>&&) //we need to use a different placeholder class here to pass the palceholders's holder type for the static_cast. : rv(std::make_unique<placeholder<I,T,LateParamsT, isCopiable>>()) {} /** \fn RefVal (const RefVal& rhs) * \brief copy constructor, copy the wrapper with the right wrapper type. * \param const RefVal& rhs : the wrapper to copy. */ RefVal(const RefVal& rhs) { rv = rhs.rv->clone(); } /** \fn RefVal& operator= (const RefVal& rhs) * \brief affector. * \param const RefVal& rhs : the wrapper to affect. */ RefVal& operator=(const RefVal& rhs) { rv=rhs.rv->clone(); return *this; } /** \fn T& get() const * \brief get the wrapper. * \return a unique pointer to the generic wrapper interface. */ T& bind(void* params) { return rv->bind(params); } T& get() const { return rv->get(); } private: std::unique_ptr<IRefVal<T, LateParamsT, isCopiable>> rv; /**> a pointer to the generic wrapper interface.*/ }; //Classe de trait pour déterminer le type à stocker //(Interne) Cas général /** * \file fastDelegate.h * \class ToStoreImpl * \param T the type of the wrapper. * \brief Trait class which use an alias on a wrapped type. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class T> struct ToStoreImpl { using type = T; }; /** * \file fastDelegate.h * \class ToStoreImpl * \param T the type warpped in the warpper. * \brief Trait class with keep an alias on the wrapped type. * This class is specialized for std::_reference_wrapper type. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class T> struct ToStoreImpl<std::reference_wrapper<T>> { using type = T; }; /** * \file fastDelegate.h * \class ToStoreImpl * \param T the type warpped in the warpper. * \brief Trait class with keep an alias on the plcaholder's type. * This class is specialized for placeholder's type. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<size_t I, class T> struct ToStoreImpl<ph<I,T>> { using type = T; }; /** * \file fastDelegate.h * \class ToStore * \param T the type of the wrapper. * \brief Trait class with keep an alias of the wrapper type. (without the reference) * the inheritance use the right specialized templated class to hold the type of the wrapped object * depending on the wrapper type. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class T> struct ToStore : ToStoreImpl<std::remove_reference_t<T>> {}; /** * \file fastDelegate.h * \class ToStore_t * \param T the type of the wrapped object. * \brief Trait class which hold an alias to the real type of the wrapped type. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class T> using ToStore_t = typename ToStore<T>::type; /** * \file fastDelegate.h * \class DynamicWrapper * \param R the return type of the wrapped functor. * \param C the class type of the wrapped functor. * \param ArgT the arguments types of the wrapped functor. * \brief This class warp a function pointer to a member function. * I don't use an std::function directly here to keep the class type of the member function pointer * because if the passed object is polymorphic, I need to apply a dynamic cast * before calling the member function pointer on the object. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<bool B, class R, class C, class... ArgT> struct DynamicWrapper { }; template<class R, class C,class... ArgT> struct DynamicWrapper<true, R, C, ArgT...> { /**\fn DynamicWrapper(R(C::*pf)(ArgT...)) : pfunc(pf) * \brief warp a pointer to a member function. * \param R(C::*pf)(ArgT...) : the pointer to the member function. */ DynamicWrapper(R(C::*pf)(ArgT...)) : pfunc(pf){} template<class O, class... ArgU> R operator()(O* o, ArgU&&... arg) const { //std::cout<<"class : "<<typeid(C).name()<<std::endl<<"object derived : "<<typeid(o).name()<<std::endl<<"address : "<<o<<std::endl; (o->*pfunc)(std::forward<ArgU>(arg)...); } template<class O, class... ArgU> R operator()(O o, ArgU&&... arg) const { //std::cout<<"class : "<<typeid(C).name()<<std::endl<<"object derived : "<<typeid(o).name()<<std::endl<<"address : "<<o<<std::endl; (o.*pfunc)(std::forward<ArgU>(arg)...); } /**\fn R operator()(O o, ArgU&&... arg) const * \brief call the member function's pointer with he given object and the given argument * \param O o : the object onwich to call the member function's pointer. * \param ArgU&& arg : the arguments of the member function's pointer to call. */ /*template<class O, class... ArgU> R operator()(O o, ArgU&&... arg) const { return (o.*pfunc)(std::forward<ArgU>(arg)...); }*/ private: R (C::*pfunc)(ArgT...); /**> a pointer to a member's function.*/ }; template<class R, class C, class... ArgT> struct DynamicWrapper<false, R, C, ArgT...> { /**\fn DynamicWrapper(R(C::*pf)(ArgT...)) : pfunc(pf) * \brief warp a pointer to a member function. * \param R(C::*pf)(ArgT...) : the pointer to the member function. */ DynamicWrapper(R(C::*pf)(ArgT...)) : pfunc(pf){} /**\fn R operator()(O* o, ArgU&&... arg) const * \brief call the member function's pointer witht he given object and the given argument * apply a dynamic_cast in case of the type of the object and the type of the classe containing the member function * are not the same. (If the object is polymoprhic) * If the cast fails it means that the object is not polymorphic so it throws an error. * \param O* o : the object onwich to call the member function's pointer. * \param ArgU&& arg : the arguments of the member function's pointer to call. */ template<class O, class... ArgU> R operator()(O* o, ArgU&&... arg) const { //std::cout<<"class : "<<typeid(C).name()<<std::endl<<"object derived : "<<typeid(o).name()<<std::endl<<"address : "<<o<<std::endl; if(dynamic_cast<C*>(o)) return (dynamic_cast<C*>(o)->*pfunc)(std::forward<ArgU>(arg)...); throw Erreur(0, "Invalid cast : types are nor polymorphic!", 1); } template<class O, class... ArgU> R operator()(O& o, ArgU&&... arg) const { //std::cout<<"class : "<<typeid(C).name()<<std::endl<<"object derived : "<<typeid(o).name()<<std::endl<<"address : "<<o<<std::endl; if(dynamic_cast<C&>(o)) return (dynamic_cast<C&>(o).*pfunc)(std::forward<ArgU>(arg)...); throw Erreur(0, "Invalid cast : types are nor polymorphic!", 1); } R (C::*pfunc)(ArgT...); }; /** * \file fastDelegate.h * \class DynamicFunction * \param F the type of the function. * \brief Generic class for every functors type. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class F> class DynamicFunction; /** * \file fastDelegate.h * \class DynamicFunction * \param R the return type of the function. * \param ArgT... the type of the arguments of the function. * \brief Specialized template class for functors. (inherit from std::function) * build a functor with the right constructor depending a the pointer's function type. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class R, class... ArgT> class DynamicFunction<R(ArgT...)> : std::function<R(ArgT...)> { /**> just an alias to the type of the base class.*/ using Base = std::function<R(ArgT...)>; public: /** * \fn DynamicFunction(F&& f) * \brief pass a functor to the std::function. * \param F&& f : the functor to pass to the std::function. */ template<class F> DynamicFunction(F&& f) : Base(std::forward<F>(f)) {} /** \fn DynamicFunction (R (C::*pf)(ArgU...)) * \brief pass a pointer to a member's function to the DynamicWrapper, and then * pass this wrapper to the std::function, so, the std::function call the operator() of the DynamicWrapper class * and not the operator() of the std::function class so we can perform the dynamic_cast if necessary. * \param R(C::*pf)(ArgU...) : the pointer to the member's function. * \ */ template<class C, class... ArgU> DynamicFunction(R(C::*pf)(ArgU...)) : Base(DynamicWrapper<std::is_same<C, ToStore_t<std::remove_reference_t<std::tuple_element_t<0, std::tuple<ArgT...>>>>>::value, R,C, ArgU...>(pf)) {} /**> we use the operator() of the base class.*/ using Base::operator(); }; /** * \file fastDelegate.h * \class Delegate * \param R the return type of the function. * \brief Interface with can hold a delegate to every delegates types. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class R> struct Delegate { /**\fn Delegate() * \brief default constructor. */ Delegate() =default; /**\fn virtual std::unique_ptr<Delegate> clone() const = 0; * \brief pure virtual function to redefine in the subclass to copy the delegate. * \return std::unique_ptr<Delegate> a pointer to the copied delegate. */ virtual std::unique_ptr<Delegate> clone() const = 0; /**\fn void bind(void* params) = 0; * \brief pure virtual function to redefines to bind parameters. * \param void* : address of placeholders's holder. */ virtual void bind(void* params) = 0; /**\fn R operator()() = 0; * \brief pure virtual function to redefines to call the std::function of the delegate. * \return R : return the value returned by the std::function. */ virtual R operator()() = 0; /** /fn virtual Delegate() * \brief destructor */ virtual ~Delegate(){} protected: /** * \fn Delegate (const Delegate&) {} * \brief copy constructor. * \param const Delegate& : the delegate to copy. */ Delegate(const Delegate&){} /** * \fn Delegate& operator= (const Delegate&) {} * \brief affector. * \return Delegate& : return a reference to the current delegate. */ Delegate& operator=(const Delegate&) { return *this; } }; /** * \file fastDelegate.h * \class FastDelegateImpl * \brief Implementation of the delegate's interfaces. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class R, class... ArgT> struct FastDelegateImpl : Delegate<R> { /** \fn FastDelegateImpl(F&& f, ArgU&&... arg) * \brief constructor : create the delegate with the functor and the arguments value passed. */ template<class F, class... ArgU> FastDelegateImpl(F&& f, ArgU&&... arg) : func(std::forward<F>(f)) , param(std::forward<ArgU>(arg)...) , tmpParam(std::forward<ArgU>(arg)...) {} /** \fn std::unique_ptr<Delegate<R>> clone() const * \brief make a copy of the delegate. * \return the copied delegate. */ std::unique_ptr<Delegate<R>> clone() const { return std::make_unique<FastDelegateImpl>(*this); } /** \fn void bind(void* params) * \brief bind each placeholders's parameters's values depending on the placeholders's positions and store them into the tuple. * \param the address of the placeholders's holder. */ void bind(void* params) { param = tmpParam; bindParams(params); } /** \fn R operator()() * \brief changed the parameter's values of the std::function. * \param ArgU&&... args : the values for the parameters to the delegate's function. */ R operator()() { return call(std::make_index_sequence<sizeof...(ArgT)>()); } /** \fn setParams(ArgU&&... arg) * \brief change parameters values of the delegate's function. * \param ArgU&&... args : the values for the parameters to the delegate's function. */ template<class... ArgU> void setParams(ArgU&&... arg) { param=std::make_tuple(std::forward<ArgU>(arg)...); tmpParam=std::make_tuple(std::forward<ArgU>(arg)...); } private: /** * \fn bindParams(void* params) * \brief final case, we stop recursion when each placeholder's parameters are binded. * \param the address of the placeholders's holder. */ template <std::size_t I = 0> typename std::enable_if<I == sizeof...(ArgT)>::type bindParams(void* params) { } /** * \fn bindParams(void* params) * \brief intermediate case, we do recursion for each tuple elements to bind the placeholders's parameters's values. * \param the address of the placeholders's holder. */ template <std::size_t I = 0> typename std::enable_if<(I < sizeof...(ArgT))>::type bindParams(void* params) { std::get<I>(param) = std::get<I>(param).bind(params); bindParams<I+1>(params); } /** \fn R call(std::index_sequence<I...>) * \brief pass each elements of the tuple to the std::function and unwarp them. * \param std::index_sequence<I...> : a sequence of indexes to get every elements of the tuple. * \return the value returned by the std::function. */ template<std::size_t... I> R call(std::index_sequence<I...>) const { return func(std::get<I>(param).get()...); } DynamicFunction<R(ToStore_t<ArgT>&...)> func; /**> a functor whith hold the pointer to a callback function.*/ /** * We need to remove every types which are not placeholders, we also need to remove same placeholder's types, * and finally we also need to sort them. * We also remove cv qualifier's and we pass the placeholders's types to the LateParameters class. */ using tuple_t = typename meta::sort<LessPlaceceholder, typename meta::unique<typename meta::copy_if<is_placeholder, std::tuple<std::remove_cv_t<ArgT>...>>::f>::f>::f; using late_params_t = typename meta::lift<tuple_t, LateParameters, std::make_index_sequence<std::tuple_size<tuple_t>::value>>::f; /**> alias to the placeholders's holder.*/ //We need to use two tuples here, one to store parameters values and another to store parameters values after the placeholders's values are binded. //jln lib doesn't compile on mscv so I created my own lib for meta functions. /*using late_params_t = jln::mp::copy_if<jln::mp::lift<is_placeholder>, jln::mp::unique<jln::mp::sort<LessPlaceceholder, jln::mp::lift<LateParameters>>>> ::f<std::remove_cv_t<ArgT>...>;*/ std::tuple<RefVal<ToStore_t<ArgT>, late_params_t, std::is_copy_constructible_v<ToStore_t<ArgT>>>...> param; /**> the wrapped values of the parameters to pass to the callback's function.*/ std::tuple<RefVal<ToStore_t<ArgT>, late_params_t, std::is_copy_constructible_v<ToStore_t<ArgT>>>...> tmpParam; /**> the wrapped values of the temporary parameters (parameters with placeholder's types).*/ }; /** * \file fastDelegate.h * \class FastDelegate * \brief Class used for the type erasure, * which allow the user be able to store a set of different callback's functions types with the same return type. * I use this class essentially to connect signals and slots. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class R> struct FastDelegate { /**\fn default constructor */ FastDelegate() { delegate = nullptr; }; /**\fn FastDelegate (F&& f, Arg&& arf) * \param F&& f : the functor to pass. * \param Arg&&... arg : arguments to pass to the functor. */ template<class F, class... Arg> FastDelegate(F&& f, Arg&&... arg) : delegate(std::make_unique <FastDelegateImpl<R,std::remove_reference_t<Arg>...>> (std::forward<F>(f),std::forward<Arg>(arg)...) ) {} /**\fn FastDelegate (FastDelegate& rhs) * \brief copy constructor. * \param FastDelegate& rhs : the delegate to copy. */ FastDelegate(FastDelegate& rhs) : delegate(rhs.delegate->clone()) {} /**\fn FastDelegate (const FastDelegate& rhs) * \brief copy constructor. * \param const FastDelegate& rhs : the delegate to copy. */ FastDelegate(const FastDelegate& rhs) : delegate(rhs.delegate->clone()) {} /**\fn FastDelegate (FastDelegate& rhs) * \brief move constructor. * \param FastDelegate&& rhs : the delegate to move. */ FastDelegate(FastDelegate&& rhs) =default; /**\fn FastDelegate& operator= (FastDelegate& rhs) * \brief affect the content of the delegate to the delegate. * \param const FastDelegate& rhs : the delegate affect. * \return FastDelegate& : the affected delegate. */ FastDelegate& operator=(const FastDelegate& rhs) { return operator=(FastDelegate(rhs)); } /**\fn FastDelegate& operator= (FastDelegate& rhs) * \brief affect and move the content of the delegate to the delegate. * \param const FastDelegate& rhs : the delegate to move and to affect. * \return FastDelegate& : the moved and affected delegate. */ FastDelegate& operator=(FastDelegate&&) =default; /**\fn void bind(Arg&&... arg) * \brief bind each arguments for placeholders. * \param the arguments the bind. */ template <typename... Arg> void bind(Arg&&... arg) { void* params = bind_impl(std::index_sequence_for<Arg...>(), static_cast<Arg&&>(arg)...); delegate->bind(params); delete params; } /**\fn void bind_impl(std::index_sequence<Ints...>, Args&&... args) * \brief bind each arguments for placeholders. * \param std::index_sequence<Ints...> index sequence to pass each arguments. * \param the arguments the bind. * \return pointer to the placeholders's holder's type. */ template<std::size_t... Ints, class... Args> void* bind_impl(std::index_sequence<Ints...>, Args&&... args) { //Alias to the placeholders's holder's type, we expand the parameter's packs, so the first argument is the type of placeholder 0, and so on. using params_t = LateParameters<ph<Ints, ToStore_t<Args>>...>; void* params = new params_t{static_cast<Args&&>(args)...}; return params; } /**\fn R operator()() const; * \brief call the std::function of the delegate. * \return the value returned by the std::function. */ R operator()() { if (delegate) return (*delegate)(); } /**\fn setParams(Arg&&... arg) * \brief change the parameter's values of the delegate. * \return Arg&&... arg : the values of the parameters of the delegate. */ template<class... Arg> void setParams(Arg&&... arg) { using DynamicType = FastDelegateImpl<R,std::remove_reference_t<Arg>...>*; if(dynamic_cast<DynamicType>(delegate.get())) dynamic_cast<DynamicType>(delegate.get())->setParams(std::forward<Arg>(arg)...); else throw Erreur(0, "Bad cast!", 5); } private: std::unique_ptr<Delegate<R>> delegate; /**> holds the pointer to the generic delegate.*/ };
Donc voilà.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562 #define FUN_PARAM void* p0 =nullptr, void* p1 =nullptr, void* p2 =nullptr, void* p3 =nullptr #define FWD_PARAM p0,p1,p2,p3 /** *\namespace odfaeg * the namespace of the Opensource Development Framework Adapted for Every Games. */ namespace odfaeg { namespace core { /** * \file fastDelegate.h * \class IRefVal * \brief Interface for the warppers to references, values and pointers. * This class is used store references, pointers and values to pass to the callack's functions. * \param T : the type of the value to wrap. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class T> struct IRefVal { /**\fn * \brief default constructor */ IRefVal()=default; /**\fn T& get() * \brief get the reference of the wrapped type. * \return the reference of the wrapped type. */ virtual T& bind(FUN_PARAM) = 0; virtual T& get(FUN_PARAM) = 0; /**\fn std::unique_ptr<IRefVal<T>> clone() const = 0; * \brief copy the wrapper. * \return the copied wrapper.*/ virtual std::unique_ptr<IRefVal<T>> clone() const = 0; /**\fn destructor*/ virtual ~IRefVal(){} protected: /**\fn IRefVal(const IRefVal&) * \brief constructor, pass the reference to wrap. * \param const IRefVal& : the reference to wrap. */ IRefVal(const IRefVal&){} /** \fn IRefVal& operator=(const IRefVal&) * \brief affector. * \param const IRefVal& : the wrapper to affect. * \return the affected wrapper.*/ IRefVal& operator=(const IRefVal&) { return *this; } }; /** * \file fastDelegate.h * \class Ref * \brief Warp a reference. (Use std::reference_wrapper so we can pass a reference with std::ref) * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template <typename T> class RefVal; template<class T> struct Ref : IRefVal<T> { /** *\fn Ref(const std::reference_wrapper<T>& r) *\brief Constructor : pass an std::reference_wrapper to the wrapper. *\param std::reference_wrapper<T>& r : the reference_wrapper. */ Ref(const std::reference_wrapper<T>& r) : ref(r) {} /** * \fn T& get() * \brief return a reference to an object. * \return T& the reference to the object. */ T& bind(FUN_PARAM) { return ref.get(); } T& get(FUN_PARAM) { return ref.get(); } /** * \fn std::unique_ptr<IRefVal<T>> clone() const * \brief copy the reference wrapper. * \return std::unique_ptr<IRefVal<T>> : the cloned wrapper. */ std::unique_ptr<IRefVal<T>> clone() const { return std::make_unique<Ref>(*this); } private: std::reference_wrapper<T> ref; /**> the std::reference_wrapper which warp the reference.*/ }; /** * \file fastDelegate.h * \class Val * \brief Warp a value. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class T> struct Val : IRefVal<T> { /**\fn Val(const T& t) * \brief pass a value to the wrapper. * \param const T& t : the value to pass. */ Val(const T& t) : val(t) {} /** \fn * \brief return the value * \return T& : return the value. */ T& bind(FUN_PARAM) { return val; } T& get(FUN_PARAM) { return val; } /** * \fn std::unique_ptr<IRefVal<T>> clone() const * \brief copy the value wrapper. * \return std::unique_ptr<IRefVal<T>> : the cloned wrapper. */ std::unique_ptr<IRefVal<T>> clone() const { return std::make_unique<Val>(*this); } private: T val; /**> T val : keep the value of the wrapper.*/ }; template<size_t I, class T> struct ph : IRefVal<T> { std::unique_ptr<IRefVal<T>> clone() const { return std::make_unique<ph>(*this); } T& bind(FUN_PARAM) { return *static_cast<T*> (std::get<I>(std::make_tuple(FWD_PARAM))); } T& get(FUN_PARAM) { return *static_cast<T*> (std::get<I>(std::make_tuple(FWD_PARAM))); } }; /** * \file fastDelegate.h * \class Ref * \brief Warp a pointer. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ /** * \file fastDelegate.h * \class RefVal * \brief Wrap a pointer, a value or a reference and keep a pointer to the generic wrapper. * Call the right constructor depending on the wrapper's or value's type. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class T> struct RefVal { /** * \fn RefVal (const T& t) * \brief constructor : construct a wrapper to a value * \param const T& t : the value to */ RefVal(const T& t) : rv(std::make_unique<Val<T>>(t)) {} /** * \fn RefVal (const std::reference_wrapper<T>& r) * \brief constructor : construct a wrapper to an std::reference_wrapper. * \param const std::reference_wrapper<T>& : the std::reference_wrapper to pass. */ RefVal(const std::reference_wrapper<T>& r) : rv(std::make_unique<Ref<T>>(r)) {} /** \fn RefVal (const RefVal& rhs) * \brief copy constructor, copy the wrapper with the right wrapper type. * \param const RefVal& rhs : the wrapper to copy. */ template<size_t I> RefVal(ph<I,T>&&) : rv(std::make_unique<ph<I,T>>()) {} RefVal(const RefVal& rhs) { rv = rhs.rv->clone(); } /** \fn RefVal& operator= (const RefVal& rhs) * \brief affector. * \param const RefVal& rhs : the wrapper to affect. */ RefVal& operator=(const RefVal& rhs) { rv=rhs.rv->clone(); return *this; } /** \fn T& get() const * \brief get the wrapper. * \return a unique pointer to the generic wrapper interface. */ T& bind(FUN_PARAM) { return rv->bind(FWD_PARAM); } template<class... Arg> T& get(Arg&&... arg) const { return rv->get(std::forward<Arg>(arg)...); } private: std::unique_ptr<IRefVal<T>> rv; /**> a pointer to the generic wrapper interface.*/ }; //Classe de trait pour déterminer le type à stocker //(Interne) Cas général /** * \file fastDelegate.h * \class ToStoreImpl * \param T the type of the wrapper. * \brief Trait class which use an alias on a wrapped type. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class T> struct ToStoreImpl { using type = T; }; /** * \file fastDelegate.h * \class ToStoreImpl * \param T the type warpped in the warpper. * \brief Trait class with keep an alias on the wrapped type. * This class is specialized for std::_reference_wrapper type. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class T> struct ToStoreImpl<std::reference_wrapper<T>> { using type = T; }; template<size_t I, class T> struct ToStoreImpl<ph<I,T>> { using type = T; }; /** * \file fastDelegate.h * \class ToStore * \param T the type of the wrapper. * \brief Trait class with keep an alias of the wrapper type. (without the reference) * the inheritance use the right specialized templated class to hold the type of the wrapped object * depending on the wrapper type. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class T> struct ToStore : ToStoreImpl<std::remove_reference_t<T>> {}; /** * \file fastDelegate.h * \class ToStore_t * \param T the type of the wrapped object. * \brief Trait class which hold an alias to the real type of the wrapped type. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class T> using ToStore_t = typename ToStore<T>::type; /** * \file fastDelegate.h * \class DynamicWrapper * \param R the return type of the wrapped functor. * \param C the class type of the wrapped functor. * \param ArgT the arguments types of the wrapped functor. * \brief This class warp a function pointer to a member function. * I don't use an std::function directly here to keep the class type of the member function pointer * because if the passed object is polymorphic, I need to apply a dynamic cast * before calling the member function pointer on the object. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class R, class C, class... ArgT> struct DynamicWrapper { /**\fn DynamicWrapper(R(C::*pf)(ArgT...)) : pfunc(pf) * \brief warp a pointer to a member function. * \param R(C::*pf)(ArgT...) : the pointer to the member function. */ DynamicWrapper(R(C::*pf)(ArgT...)) : pfunc(pf){} /**\fn R operator()(O* o, ArgU&&... arg) const * \brief call the member function's pointer witht he given object and the given argument * apply a dynamic_cast in case of the type of the object and the type of the classe containing the member function * are not the same. (If the object is polymoprhic) * If the cast fails it means that the object is not polymorphic so it throws an error. * \param O* o : the object onwich to call the member function's pointer. * \param ArgU&& arg : the arguments of the member function's pointer to call. */ template<class O, class... ArgU> R operator()(O* o, ArgU&&... arg) const { if(dynamic_cast<C*>(o)) return (dynamic_cast<C*>(o)->*pfunc)(std::forward<ArgU>(arg)...); throw Erreur(0, "Invalid cast : types are nor polymorphic!", 1); } private: R (C::*pfunc)(ArgT...); /**> a pointer to a member's function.*/ }; /** * \file fastDelegate.h * \class DynamicFunction * \param F the type of the function. * \brief Generic class for every functors type. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class F> class DynamicFunction; /** * \file fastDelegate.h * \class DynamicFunction * \param R the return type of the function. * \param ArgT... the type of the arguments of the function. * \brief Specialized template class for functors. (inherit from std::function) * build a functor with the right constructor depending a the pointer's function type. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class R, class... ArgT> class DynamicFunction<R(ArgT...)> : std::function<R(ArgT...)> { /**> just an alias to the type of the base class.*/ using Base = std::function<R(ArgT...)>; public: /** * \fn DynamicFunction(F&& f) * \brief pass a functor to the std::function. * \param F&& f : the functor to pass to the std::function. */ template<class F> DynamicFunction(F&& f) : Base(std::forward<F>(f)) {} /** \fn DynamicFunction (R (C::*pf)(ArgU...)) * \brief pass a pointer to a member's function to the DynamicWrapper, and then * pass this wrapper to the std::function, so, the std::function call the operator() of the DynamicWrapper class * and not the operator() of the std::function class so we can perform the dynamic_cast if necessary. * \param R(C::*pf)(ArgU...) : the pointer to the member's function. * \ */ template<class C, class... ArgU> DynamicFunction(R(C::*pf)(ArgU...)) : Base(DynamicWrapper<R,C,ArgU...>(pf)) {} /**> just an allias to the operator() of the base class.*/ using Base::operator(); }; /** * \file fastDelegate.h * \class Delegate * \param R the return type of the function. * \brief Interface with can hold a delegate to every delegates types. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class R> struct Delegate { /**\fn Delegate() * \brief default constructor. */ Delegate() =default; /**\fn virtual std::unique_ptr<Delegate> clone() const = 0; * \brief pure virtual function to redefine in the subclass to copy the delegate. * \return std::unique_ptr<Delegate> a pointer to the copied delegate. */ virtual std::unique_ptr<Delegate> clone() const = 0; /**\fn R operator()() = 0; * \brief pure virtual function to redefines to call the std::function of the delegate. * \return R : return the value returned by the std::function. */ virtual void bind(FUN_PARAM) = 0; virtual R operator()(FUN_PARAM) = 0; /** /fn virtual Delegate() * \brief destructor */ virtual ~Delegate(){} protected: /** * \fn Delegate (const Delegate&) {} * \brief copy constructor. * \param const Delegate& : the delegate to copy. */ Delegate(const Delegate&){} /** * \fn Delegate& operator= (const Delegate&) {} * \brief affector. * \return Delegate& : return a reference to the current delegate. */ Delegate& operator=(const Delegate&) { return *this; } }; /** * \file fastDelegate.h * \class FastDelegateImpl * \brief Implementation of the delegate's interfaces. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class R, class... ArgT> struct FastDelegateImpl : Delegate<R> { /** \fn FastDelegateImpl(F&& f, ArgU&&... arg) * \brief constructor : create the delegate with the functor and the arguments value passed. */ template<class F, class... ArgU> FastDelegateImpl(F&& f, ArgU&&... arg) : func(std::forward<F>(f)) , param(std::forward<ArgU>(arg)...) , tmpParam(std::forward<ArgU>(arg)...) {} /** \fn std::unique_ptr<Delegate<R>> clone() const * \brief make a copy of the delegate. * \return the copied delegate. */ std::unique_ptr<Delegate<R>> clone() const { return std::make_unique<FastDelegateImpl>(*this); } /** \fn R operator()() * \brief call the std::function of the delegate. * \return the value returned by the std::function. */ void bind(FUN_PARAM) { param = tmpParam; bindParams(FWD_PARAM); } R operator()(FUN_PARAM) { return call(std::make_index_sequence<sizeof...(ArgT)>(), FWD_PARAM); } /** \fn R operator()() * \brief changed the parameter's values of the std::function. * \param ArgU&&... args : the values for the parameters to the delegate's function. */ template<class... ArgU> void setParams(ArgU&&... arg) { param=std::make_tuple(std::forward<ArgU>(arg)...); tmpParam=std::make_tuple(std::forward<ArgU>(arg)...); } private: /** \fn R call(std::index_sequence<I...>) * \brief pass each elements of the tuple to the std::function and unwarp them. * \param std::index_sequence<I...> : a sequence of indexes to get every elements of the tuple. * \return the value returned by the std::function. */ template <std::size_t I = 0, typename... Arg> typename std::enable_if<I == sizeof...(ArgT)>::type bindParams(Arg&&... arg) { } template <std::size_t I = 0, typename... Arg> typename std::enable_if<(I < sizeof...(ArgT))>::type bindParams(Arg&&... arg) { std::get<I>(param) = std::get<I>(param).bind(std::forward<Arg>(arg)...); bindParams<I+1>(std::forward<Arg>(arg)...); } template<std::size_t... I, class... ArgU> R call(std::index_sequence<I...>, ArgU&&... args) const { return func(std::get<I>(param).get(std::forward<ArgU>(args)...)...); } DynamicFunction<R(ArgT&...)> func; /**> a functor whith hold the pointer to a callback function.*/ std::tuple<RefVal<ArgT>...> param; /**> the wrapped values of the parameters to pass to the callback's function.*/ std::tuple<RefVal<ArgT>...> tmpParam; }; /** * \file fastDelegate.h * \class FastDelegate * \brief Class used for the type erasure, * which allow the user be able to store a set of different callback's functions types with the same return type. * \author Duroisin.L * \version 1.0 * \date 1/02/2014 */ template<class R> struct FastDelegate { /**\fn default constructor */ FastDelegate() = default; /**\fn FastDelegate (F&& f, Arg&& arf) * \param F&& f : the functor to pass. * \param Arg&&... arg : arguments to pass to the functor. */ template<class F, class... Arg> FastDelegate(F&& f, Arg&&... arg) : delegate(std::make_unique <FastDelegateImpl<R,ToStore_t<Arg>...>> (std::forward<F>(f),std::forward<Arg>(arg)...) ) {} /**\fn FastDelegate (FastDelegate& rhs) * \brief copy constructor. * \param FastDelegate& rhs : the delegate to copy. */ FastDelegate(FastDelegate& rhs) : delegate(rhs.delegate->clone()) {} /**\fn FastDelegate (const FastDelegate& rhs) * \brief copy constructor. * \param const FastDelegate& rhs : the delegate to copy. */ FastDelegate(const FastDelegate& rhs) : delegate(rhs.delegate->clone()) {} /**\fn FastDelegate (FastDelegate& rhs) * \brief move constructor. * \param FastDelegate&& rhs : the delegate to move. */ FastDelegate(FastDelegate&& rhs) =default; /**\fn FastDelegate& operator= (FastDelegate& rhs) * \brief affect the content of the delegate to the delegate. * \param const FastDelegate& rhs : the delegate affect. * \return FastDelegate& : the affected delegate. */ FastDelegate& operator=(const FastDelegate& rhs) { return operator=(FastDelegate(rhs)); } /**\fn FastDelegate& operator= (FastDelegate& rhs) * \brief affect and move the content of the delegate to the delegate. * \param const FastDelegate& rhs : the delegate to move and to affect. * \return FastDelegate& : the moved and affected delegate. */ FastDelegate& operator=(FastDelegate&&) =default; /**\fn R operator()() const; * \brief call the std::function of the delegate. * \return the value returned by the std::function. */ template <typename... Arg> void bind(Arg&&... arg) const { delegate->bind(&arg...); } template<class... Arg> R operator()(Arg&&... arg) const { return (*delegate)(&arg...); } /**\fn setParams(Arg&&... arg) * \brief change the parameter's values of the delegate. * \return Arg&&... arg : the values of the parameters of the delegate. */ template<class... Arg> void setParams(Arg&&... arg) { using DynamicType = FastDelegateImpl<R,ToStore_t<Arg>...>*; if(dynamic_cast<DynamicType>(delegate.get())) dynamic_cast<DynamicType>(delegate.get())->setParams(std::forward<Arg>(arg)...); else throw Erreur(0, "Bad cast!", 5); } private: std::unique_ptr<Delegate<R>> delegate; /**> holds the pointer to the generic delegate.*/ }; } } #endif![]()
Partager