@@ -667,6 +667,205 @@ Through concepts and template specialization, we support:
667667
668668All work seamlessly with reflection!
669669
670+
671+ ---
672+
673+ # Runtime dispatching
674+
675+ - One function semantically
676+ - Several implementations
677+ - Select the best one at runtime for performance.
678+
679+
680+
681+ ---
682+
683+ # Issue: x64 processors support different instructions
684+
685+ A Zen 5 CPU and a Pentium 4 CPU can be quite different.
686+
687+ ```cpp
688+ bool has_sse2() { /* query the CPU */ }
689+ bool has_avx2() { /* query the CPU */ }
690+ bool has_avx512() { /* query the CPU */ }
691+ ```
692+
693+ These functions cannot be ` consteval ` .
694+
695+
696+ ---
697+
698+ <img src =" images/dispatching.svg " width =" 50% " >
699+
700+ ---
701+
702+ # Example: Sum function
703+
704+ ``` cpp
705+ using SumFunc = float (*)(const float *, size_t );
706+ ```
707+
708+ ---
709+
710+ # Setup a reassignable implementation
711+
712+
713+ ``` cpp
714+ SumFunc &get_sum_fnc () {
715+ static SumFunc sum_impl = sum_init;
716+ return sum_impl;
717+ }
718+ ```
719+
720+ We initialize it with some special initialization function.
721+
722+
723+
724+ ---
725+
726+ ``` cpp
727+ float sum_init (const float * data, size_t n) {
728+ SumFunc &sum_impl = get_sum_fnc();
729+ if (has_avx2()) {
730+ sum_impl = sum_avx2;
731+ } else if (has_sse2()) {
732+ sum_impl = sum_sse2;
733+ } else {
734+ sum_impl = sum_generic;
735+ }
736+ return sum_impl(data, n);
737+ }
738+ ```
739+
740+ On first call, `get_sum_fnc()` is modified, and then it will remain constant.
741+
742+ ---
743+
744+ # Runtime dispatching and metaprogramming
745+
746+ - Metaprogramming is at compile-time.
747+ - Runtime dispatching is fundamentally at runtime.
748+
749+ ---
750+
751+ # Does your string need escaping?
752+
753+
754+ - In JSON, you must escape control characters, quotes.
755+ - Most strings in practice do not need escaping.
756+
757+
758+ ```Cpp
759+ simple_needs_escaping(std::string_view v) {
760+ for (unsigned char c : v) {
761+ if(json_quotable_character[c]) { return true; }
762+ }
763+ return false;
764+ }
765+ ```
766+
767+ ---
768+
769+
770+ ## SIMD
771+
772+ - Stands for Single instruction, multiple data
773+ - Allows us to process 16 (or more) bytes or more with one instruction
774+ - Supported on all modern CPUs (phone, laptop)
775+
776+ ---
777+
778+ # SIMD (Pentium 4 and better)
779+
780+ ``` cpp
781+ __m128i word = _mm_loadu_si128(data); // load 16 bytes
782+ // check for control characters:
783+ _mm_cmpeq_epi8 (_ mm_subs_epu8(word, _ mm_set1_epi8(31)),
784+ _ mm_setzero_si128());
785+ ```
786+
787+ ---
788+
789+ # SIMD (AVX-512)
790+
791+ ```cpp
792+ __m512i word = _mm512_loadu_si512(data); // load 64 bytes
793+ // check for control characters:
794+ _mm512_cmple_epu8_mask(word, _mm512_set1_epi8(31));
795+ ```
796+
797+ ---
798+
799+ # Runtime dispatching is poor with quick functions
800+
801+ - Calling a fast function like ` fast_needs_escaping ` without inlining prevents useful optimizations.
802+ - Runtime dispatching implies a function call!
803+
804+ ---
805+
806+ # Current solution
807+
808+ - No runtime dispatching (* sad face* ).
809+ - All x64 processors support Pentium 4-level SIMD. Use that in a short function.
810+ - * Easy* if programmer builds for specific machine (` -march=native ` ), use fancier tricks.
811+
812+ ---
813+
814+ # Compile-time string escaping
815+
816+ - Often the 'keys' are known at compile time.
817+
818+
819+ ``` cpp
820+ struct Player {
821+ std::string username;
822+ int level;
823+ double health;
824+ std::vector< std::string > inventory;
825+ };
826+ ```
827+
828+ - Keys are: `username`, `level`, `health`, `inventory`.
829+
830+ ---
831+
832+ # Escape at compile time.
833+
834+ ```cpp
835+ [:expand(std::meta::nonstatic_data_members_of(...)] {
836+ constexpr auto key =
837+ std::define_static_string(consteval_to_quoted_escaped(
838+ std::meta::identifier_of(dm)));
839+ b.append_raw(key);
840+ b.append(':');
841+ // ...
842+ };
843+ ```
844+
845+ ---
846+
847+ # Otherwise tricky to do
848+
849+ - Outside metaprogramming, lots of values are compile-time constants
850+ - But processing it at compile time is not always easy/convenient.
851+
852+ ---
853+
854+ # Example: ` g ` returns 1
855+
856+ ``` cpp
857+ constexpr int convert (const char * x) {
858+ if (std::is_constant_evaluated()) { return 0; }
859+ return 1;
860+ }
861+
862+ int g() {
863+ constexpr char key[ ] = "name";
864+ auto x = convert(key);
865+ return x;
866+ }
867+ ```
868+
670869---
671870
672871# Conclusion
0 commit comments