C++ - Reddit
226 subscribers
48 photos
8 videos
24.6K links
Stay up-to-date with everything C++!
Content directly fetched from the subreddit just for you.

Join our group for discussions : @programminginc

Powered by : @r_channels
Download Telegram
this way. Users are
obliged to use suppressions if they wish to avoid this noise.

* ==================== FIXED BUGS ====================

The following bugs have been fixed or resolved. Note that "n-i-bz"
stands for "not in bugzilla" -- that is, a bug that was reported to us
but never got a bugzilla entry. We encourage you to file bugs in
bugzilla () rather
than mailing the developers (or mailing lists) directly -- bugs that
are not entered into bugzilla tend to get forgotten about or ignored.

290061 pie elf always loaded at 0x108000
396415 Valgrind is not looking up $ORIGIN rpath of shebang programs
420682 io_pgetevents is not supported
468575 Add support for RISC-V
469782 Valgrind does not support zstd-compressed debug sections
487296 --track-fds=yes and --track-fds=all report erroneous information
when fds 0, 1, or 2 are used as non-std
489913 WARNING: unhandled amd64-linux syscall: 444 (landlock_create_ruleset)
493433 Add --modify-fds=[no|high\] option
494246 syscall fsopen not wrapped
494327 Crash when running Helgrind built with #define TRACE_PTH_FNS 1
494337 All threaded applications cause still holding lock errors
495488 Add FreeBSD getrlimitusage syscall wrapper
495816 s390x: Fix disassembler segfault for C[G\]RT and CL[G\]RT
495817 s390x: Disassembly to match objdump -d output
496370 Illumos: signal handling is broken
496571 False positive for null key passed to bpf_map_get_next_key syscall.
496950 s390x: Fix hardware capabilities and EmFail codes
497130 Recognize new DWARF5 DW_LANG constants
497455 Update drd/scripts/download-and-build-gcc
497723 Enabling Ada demangling breaks callgrind differentiation between
overloaded functions and procedures
498037 s390x: Add disassembly checker
498143 False positive on EVIOCGRAB ioctl
498317 FdBadUse is not a valid CoreError type in a suppression
even though it's generated by --gen-suppressions=yes
498421 s390x: support BPP, BPRP and NIAI insns
498422 s390x: Fix VLRL and VSTRL insns
498492 none/tests/amd64/lzcnt64 crashes on FreeBSD compiled with clang
498629 s390x: Fix S[L\]HHHR and S[L\]HHLR insns
498632 s390x: Fix LNGFR insn
498942 s390x: Rework s390_disasm interface
499183 FreeBSD: differences in avx-vmovq output
499212 mmap() with MAP_ALIGNED() returns unaligned pointer
501119 memcheck/tests/pointer-trace fails when run on NFS filesystem
501194 Fix ML_(check_macho_and_get_rw_loads) so that it is correct for
any number of segment commands
501348 glibc built with -march=x86-64-v3 does not work due to ld.so memcmp
501479 Illumos DRD pthread_mutex_init wrapper errors
501365 syscall userfaultfd not wrapped
501846 Add x86 Linux shm wrappers
501850 FreeBSD syscall arguments 7 and 8 incorrect.
501893 Missing suppression for __wcscat_avx2 (strcat-strlen-avx2.h.S:68)?
502126 glibc 2.41 extra syscall_cancel frames
502288 s390x: Memcheck false positives with NNPA last tensor dimension
502324 s390x: Memcheck false positives with TMxx and TM/TMY
502679 Use LTP for testing valgrind
502871 Make Helgrind "pthread_cond_{signal,broadcast}: dubious: associated
lock is not held by any thread" optional


https://redd.it/1kawl4q
@r_cpp
Kokkos vs OpenMP performance on multi-core CPUs?

Does anyone have experience on OpenMP vs Kokkos performance on multicore CPUs? I am seeing papers on its GPU performance, but when I tested Kokkos against a basic OpenMP implementation of 2D Laplace equation with Jacobi, I saw a 3-4x difference (with OpenMP being the faster one). Not sure if I am doing it right since I generated the Kokkos code using an LLM. I wanted to see if its worth it before getting into it.
The OpenMP code itself is slower than a pure MPI implementation, but from what I am reading in textbooks thats well expected. I am also seeing no difference in speed for the equivalent Fortran and C++ codes.

The Kokkos code: (generated via LLM): Takes about 6-7 seconds on my PC with 16 OMP threads

#include <iostream>
#include <cmath>   // For std::abs, std::max (Kokkos::abs used in kernel)
#include <cstdlib> // For std::rand, RANDMAX
#include <ctime>   // For std::time
#include <utility> // For std::swap

#include <KokkosCore.hpp>

#define NX (128 8 + 2) // Grid points in X direction (including boundaries)
#define NY (128 6 + 2) // Grid points in Y direction (including boundaries)
#define MAXITER 10000   // Maximum number of iterations
#define TOL 1.0e-6       // Tolerance for convergence


int main(int argc, char* argv[]) {
    // Initialize Kokkos. This should be done before any Kokkos operations.
    Kokkos::initialize(argc, argv);
    {

        std::cout << "Using Kokkos with execution space: " << Kokkos::DefaultExecutionSpace::name() << std::endl;
        Kokkos::View<double**> phi
A("phiA", NX, NY);
        Kokkos::View<double**> phi
B("phiB", NX, NY);

        // Host-side view for initialization.
        Kokkos::View<double**, Kokkos::HostSpace> phi
inithost("phiinithost", NX, NY);

        std::srand(static
cast<unsigned int>(std::time(nullptr))); // Seed random number generator
        for (int j = 0; j < NY; ++j) {
            for (int i = 0; i < NX; ++i) {
                phiinithost(i, j) = staticcast<double>(std::rand()) / RANDMAX;
            }
        }

        for (int i = 0; i < NX; ++i) { // Iterate over x-direction
            phiinithost(i, 0) = 0.0;
            phiinithost(i, NY - 1) = 0.0;
        }
        // For columns (left and right boundaries: x=0 and x=NX-1)
        for (int j = 0; j < NY; ++j) { // Iterate over y-direction
            phiinithost(0, j) = 0.0;
            phiinithost(NX - 1, j) = 0.0;
        }

        Kokkos::deepcopy(phiA, phiinithost);
        Kokkos::deepcopy(phiB, phiinithost); .
        Kokkos::fence("InitialDataCopyToDeviceComplete");

        std::cout << "Start solving with Kokkos (optimized with ping-pong buffering)..." << std::endl;
        Kokkos::Timer timer; // Kokkos timer for measuring wall clock time

        Kokkos::View<double> phi_current_ptr = &phi_A;
        Kokkos::View<double>
phinextptr = &phiB;

        int iter;
        double maxres = 0.0; // Stores the maximum residual found in an iteration

        for (iter = 1; iter <= MAX
ITER; ++iter) {
            auto& Pold = *phicurrentptr; // View to read from (previous iteration's values)
            auto& P
new = phi_next_ptr;   // View to write to (current iteration's values)
            Kokkos::parallel_for("JacobiUpdate",
                Kokkos::MDRangePolicy<Kokkos::Rank<2>>({1, 1}, {NY - 1, NX - 1}),
                // KOKKOS_FUNCTION: Marks lambda for device compilation.
                [=] KOKKOS_FUNCTION (const int j, const int i) { // j: y-index, i: x-index
                    P_new(i, j) = 0.25
(Pold(i + 1, j) + Pold(i - 1, j) +
                                          Pold(i, j + 1) + Pold(i, j - 1));
                });
            maxres = 0.0; // Reset maxres for the current iteration's reduction (host
Kokkos vs OpenMP performance on multi-core CPUs?

Does anyone have experience on OpenMP vs Kokkos performance on multicore CPUs? I am seeing papers on its GPU performance, but when I tested Kokkos against a basic OpenMP implementation of 2D Laplace equation with Jacobi, I saw a 3-4x difference (with OpenMP being the faster one). Not sure if I am doing it right since I generated the Kokkos code using an LLM. I wanted to see if its worth it before getting into it.
The OpenMP code itself is slower than a pure MPI implementation, but from what I am reading in textbooks thats well expected. I am also seeing no difference in speed for the equivalent Fortran and C++ codes.

The Kokkos code: (generated via LLM): Takes about 6-7 seconds on my PC with 16 OMP threads

#include <iostream>
#include <cmath>   // For std::abs, std::max (Kokkos::abs used in kernel)
#include <cstdlib> // For std::rand, RAND_MAX
#include <ctime>   // For std::time
#include <utility> // For std::swap

#include <Kokkos_Core.hpp>

#define NX (128 * 8 + 2) // Grid points in X direction (including boundaries)
#define NY (128 * 6 + 2) // Grid points in Y direction (including boundaries)
#define MAX_ITER 10000   // Maximum number of iterations
#define TOL 1.0e-6       // Tolerance for convergence


int main(int argc, char* argv[]) {
    // Initialize Kokkos. This should be done before any Kokkos operations.
    Kokkos::initialize(argc, argv);
    {

        std::cout << "Using Kokkos with execution space: " << Kokkos::DefaultExecutionSpace::name() << std::endl;
        Kokkos::View<double**> phi_A("phi_A", NX, NY);
        Kokkos::View<double**> phi_B("phi_B", NX, NY);

        // Host-side view for initialization.
        Kokkos::View<double**, Kokkos::HostSpace> phi_init_host("phi_init_host", NX, NY);

        std::srand(static_cast<unsigned int>(std::time(nullptr))); // Seed random number generator
        for (int j = 0; j < NY; ++j) {
            for (int i = 0; i < NX; ++i) {
                phi_init_host(i, j) = static_cast<double>(std::rand()) / RAND_MAX;
            }
        }

        for (int i = 0; i < NX; ++i) { // Iterate over x-direction
            phi_init_host(i, 0) = 0.0;
            phi_init_host(i, NY - 1) = 0.0;
        }
        // For columns (left and right boundaries: x=0 and x=NX-1)
        for (int j = 0; j < NY; ++j) { // Iterate over y-direction
            phi_init_host(0, j) = 0.0;
            phi_init_host(NX - 1, j) = 0.0;
        }

        Kokkos::deep_copy(phi_A, phi_init_host);
        Kokkos::deep_copy(phi_B, phi_init_host); .
        Kokkos::fence("InitialDataCopyToDeviceComplete");

        std::cout << "Start solving with Kokkos (optimized with ping-pong buffering)..." << std::endl;
        Kokkos::Timer timer; // Kokkos timer for measuring wall clock time

        Kokkos::View<double**>* phi_current_ptr = &phi_A;
        Kokkos::View<double**>* phi_next_ptr = &phi_B;

        int iter;
        double maxres = 0.0; // Stores the maximum residual found in an iteration

        for (iter = 1; iter <= MAX_ITER; ++iter) {
            auto& P_old = *phi_current_ptr; // View to read from (previous iteration's values)
            auto& P_new = *phi_next_ptr;   // View to write to (current iteration's values)
            Kokkos::parallel_for("JacobiUpdate",
                Kokkos::MDRangePolicy<Kokkos::Rank<2>>({1, 1}, {NY - 1, NX - 1}),
                // KOKKOS_FUNCTION: Marks lambda for device compilation.
                [=] KOKKOS_FUNCTION (const int j, const int i) { // j: y-index, i: x-index
                    P_new(i, j) = 0.25 * (P_old(i + 1, j) + P_old(i - 1, j) +
                                          P_old(i, j + 1) + P_old(i, j - 1));
                });
            maxres = 0.0; // Reset maxres for the current iteration's reduction (host
variable)
            Kokkos::parallel_reduce("MaxResidual",
                Kokkos::MDRangePolicy<Kokkos::Rank<2>>({1, 1}, {NY - 1, NX - 1}),
                [=] KOKKOS_FUNCTION (const int j, const int i, double& local_maxres) { // j: y-index, i: x-index
                    double point_residual_val = Kokkos::fabs(
                        0.25 * (P_new(i + 1, j) + P_new(i - 1, j) +
                                P_new(i, j + 1) + P_new(i, j - 1)) -
                        P_new(i, j)
                    );
                   
                    if (point_residual_val > local_maxres) {
                        local_maxres = point_residual_val;
                    }
                }, Kokkos::Max<double>(maxres)); // Kokkos::Max reducer updates host variable 'maxres'
           
            Kokkos::fence("ResidualCalculationComplete");
            if (iter % 100 == 0) {
                std::cout << "Iter: " << iter << " maxres: " << maxres << std::endl;
            }
            if (maxres < TOL) {
                break; // Exit loop if converged
            }
            std::swap(phi_current_ptr, phi_next_ptr);
        }
       
        Kokkos::fence("SolverLoopComplete");
        double end_time = timer.seconds();

        std::cout << "Time taken (seconds): " << end_time << std::endl;

    }
   
    Kokkos::finalize();

    return 0;
}

The OpenMP code: Takes between 1.2-2.5 seconds on my PC with 16 OMP threads

   


#include <iostream>
    #include <cmath>
    #include <cstdlib>
    #include <ctime>
    #include <omp.h>

    #define NX (128 * 8 + 2)
    #define NY (128 * 6 + 2)
    #define MAX_ITER 10000
    #define TOL 1.0e-6
    #define DX (1.0 / (NX - 1))
    #define DY (1.0 / (NY - 1))

    int main() {
        std::cout << "Start \n";
        std::cout << "Nx="<<NX<<", NY="<<NY<<"\n";
        double phi_old[NX][NY];
        double phi_new[NX][NY];
        double residual[NX][NY];
        double maxres, diff;
        int iter, i, j;

        int num_threads = omp_get_max_threads();
        std::cout << "Using " << num_threads << " OpenMP threads\n";

        std::srand(static_cast<unsigned int>(std::time(nullptr)));
        for (j = 0; j < NY; ++j)
            for (i = 0; i < NX; ++i)
                phi_old[i][j] = static_cast<double>(std::rand()) / RAND_MAX;

        for (j = 0; j < NY; ++j)
            for (i = 0; i < NX; ++i)
                phi_new[i][j] = phi_old[i][j];

        for (i = 0; i < NX; ++i) {
            phi_old[i][0] = phi_old[i][NY - 1] = 0.0;
            phi_new[i][0] = phi_new[i][NY - 1] = 0.0;
        }
        for (j = 0; j < NY; ++j) {
            phi_old[0][j] = phi_old[NX - 1][j] = 0.0;
            phi_new[0][j] = phi_new[NX - 1][j] = 0.0;
        }

        std::cout << "Start solving...\n";
        double start_time = omp_get_wtime();

        for (iter = 1; iter <= MAX_ITER; ++iter) {
            maxres = 0.0;

            #pragma omp parallel default(shared) private(i, j)
            {
                // phi_old=phi_new. Would be more efficient to switch pointers.
                #pragma omp for schedule(static)
                for (i = 0; i < NX; ++i)
                    for (j = 0; j < NY; ++j)
                    phi_old[i][j] = phi_new[i][j];

                // Jacobi
                #pragma omp for schedule(static)
                for (i = 1; i < NX-1; ++i)
                    for (j = 1; j < NY-1; ++j)  
                        phi_new[i][j] = 0.25 * (
                            phi_old[i + 1][j] + phi_old[i - 1][j] +
                            phi_old[i][j + 1] + phi_old[i][j - 1]);

                // calculate Linf residue
               
UFCS toy

Here's a toy program that tries to give UFCS (Uniform Function Call Syntax)
to a collection of standard C functions. This is either a proof of concept,
or a proof of procrastination, I'm not sure which.

---

#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cctype>

#define MAKE_UFCS_FUNC_STD(func) template<class... Types> auto func(Types... args) { \
return ufcs<decltype(std::func(value, args...))>(std::func(value, args...)); \
}

// The 'this' argument is at back of arg list.
#define MAKE_UFCS_FUNC_STD_B(func) template<class... Types> auto func(Types... args) { \
return ufcs<decltype(std::func(args..., value))>(std::func(args..., value)); \
}

template<typename T>
class ufcs
{
public:
T value;
ufcs(T aValue):value(aValue){}
operator T(){
return value;
}

MAKE_UFCS_FUNC_STD(acos )
MAKE_UFCS_FUNC_STD(asin )
MAKE_UFCS_FUNC_STD(atan )
MAKE_UFCS_FUNC_STD(atan2 )
MAKE_UFCS_FUNC_STD(cos )
MAKE_UFCS_FUNC_STD(sin )
MAKE_UFCS_FUNC_STD(tan )
MAKE_UFCS_FUNC_STD(acosh )
MAKE_UFCS_FUNC_STD(asinh )
MAKE_UFCS_FUNC_STD(atanh )
MAKE_UFCS_FUNC_STD(cosh )
MAKE_UFCS_FUNC_STD(sinh )
MAKE_UFCS_FUNC_STD(tanh )
MAKE_UFCS_FUNC_STD(exp )
MAKE_UFCS_FUNC_STD(exp2 )
MAKE_UFCS_FUNC_STD(expm1 )
MAKE_UFCS_FUNC_STD(frexp )
MAKE_UFCS_FUNC_STD(ilogb )
MAKE_UFCS_FUNC_STD(ldexp )
MAKE_UFCS_FUNC_STD(log )
MAKE_UFCS_FUNC_STD(log10 )
MAKE_UFCS_FUNC_STD(log1p )
MAKE_UFCS_FUNC_STD(log2 )
MAKE_UFCS_FUNC_STD(logb )
MAKE_UFCS_FUNC_STD(modf )
MAKE_UFCS_FUNC_STD(scalbn )
MAKE_UFCS_FUNC_STD(scalbln )
MAKE_UFCS_FUNC_STD(cbrt )
MAKE_UFCS_FUNC_STD(abs )
MAKE_UFCS_FUNC_STD(fabs )
MAKE_UFCS_FUNC_STD(hypot )
MAKE_UFCS_FUNC_STD(pow )
MAKE_UFCS_FUNC_STD(sqrt )
MAKE_UFCS_FUNC_STD(erf )
MAKE_UFCS_FUNC_STD(erfc )
MAKE_UFCS_FUNC_STD(lgamma )
MAKE_UFCS_FUNC_STD(tgamma )
MAKE_UFCS_FUNC_STD(ceil )
MAKE_UFCS_FUNC_STD(floor )
MAKE_UFCS_FUNC_STD(nearbyint )
MAKE_UFCS_FUNC_STD(rint )
MAKE_UFCS_FUNC_STD(lrint )
MAKE_UFCS_FUNC_STD(llrint )
MAKE_UFCS_FUNC_STD(round )
MAKE_UFCS_FUNC_STD(lround )
MAKE_UFCS_FUNC_STD(llround )
MAKE_UFCS_FUNC_STD(trunc )
MAKE_UFCS_FUNC_STD(fmod )
MAKE_UFCS_FUNC_STD(remainder )
MAKE_UFCS_FUNC_STD(remquo )
MAKE_UFCS_FUNC_STD(copysign )
MAKE_UFCS_FUNC_STD(nan )
MAKE_UFCS_FUNC_STD(nextafter )
MAKE_UFCS_FUNC_STD(nexttoward )
MAKE_UFCS_FUNC_STD(fdim )
MAKE_UFCS_FUNC_STD(fmax )
MAKE_UFCS_FUNC_STD(fmin )
MAKE_UFCS_FUNC_STD(fma )
MAKE_UFCS_FUNC_STD(fpclassify )
MAKE_UFCS_FUNC_STD(isfinite )
MAKE_UFCS_FUNC_STD(isinf )
MAKE_UFCS_FUNC_STD(isnan )
MAKE_UFCS_FUNC_STD(isnormal )
MAKE_UFCS_FUNC_STD(signbit )
MAKE_UFCS_FUNC_STD(isgreater )
MAKE_UFCS_FUNC_STD(isgreaterequal )
MAKE_UFCS_FUNC_STD(isless )
MAKE_UFCS_FUNC_STD(islessequal )
MAKE_UFCS_FUNC_STD(islessgreater )
MAKE_UFCS_FUNC_STD(isunordered )
MAKE_UFCS_FUNC_STD(assoc_laguerre )
MAKE_UFCS_FUNC_STD(assoc_legendre )
MAKE_UFCS_FUNC_STD(beta )
MAKE_UFCS_FUNC_STD(betaf )
MAKE_UFCS_FUNC_STD(strlen )
MAKE_UFCS_FUNC_STD(system )
MAKE_UFCS_FUNC_STD(calloc )
MAKE_UFCS_FUNC_STD(free )
MAKE_UFCS_FUNC_STD(malloc )
MAKE_UFCS_FUNC_STD(realloc )
MAKE_UFCS_FUNC_STD(atof )
MAKE_UFCS_FUNC_STD(atoi )
MAKE_UFCS_FUNC_STD(atol )
MAKE_UFCS_FUNC_STD(atoll )
MAKE_UFCS_FUNC_STD(strtod )
MAKE_UFCS_FUNC_STD(strtof )
MAKE_UFCS_FUNC_STD(strtold )
MAKE_UFCS_FUNC_STD(strtol )
MAKE_UFCS_FUNC_STD(strtoll )
MAKE_UFCS_FUNC_STD(strtoul )
MAKE_UFCS_FUNC_STD(strtoull )
MAKE_UFCS_FUNC_STD(mblen )
MAKE_UFCS_FUNC_STD(mbtowc )
MAKE_UFCS_FUNC_STD(wctomb )
MAKE_UFCS_FUNC_STD(mbstowcs )
MAKE_UFCS_FUNC_STD(wcstombs )
MAKE_UFCS_FUNC_STD(bsearch )
MAKE_UFCS_FUNC_STD(qsort )
MAKE_UFCS_FUNC_STD(srand )
MAKE_UFCS_FUNC_STD(labs )
MAKE_UFCS_FUNC_STD(llabs )
MAKE_UFCS_FUNC_STD(div )
MAKE_UFCS_FUNC_STD(ldiv )
MAKE_UFCS_FUNC_STD(lldiv )
};

#include <iostream>
#include <iomanip>

#define PRINT(a) cout << #a ": " << (a) << endl

int main()
{
using namespace std;
auto a = ufcs(1.0);
PRINT(a);
PRINT(a.sin());
PRINT(a.sin().asin());
a = 2.718;
PRINT(a);
PRINT(a.log());
PRINT(a.log().exp());

auto f = ufcs(fopen("out.txt", "w"));
f.fprintf("This\nis\na\ntest\n");
f.fflush();
f.fclose();

f = ufcs(fopen("out.txt", "r"));
char buffer[80];
auto b = ufcs(buffer);
while(f.fgets(buffer, sizeof(buffer)))
{
cout << b ;
}
f.fclose();

b.strcpy("Hello");
PRINT(b);
PRINT(b.strstr("l"));
PRINT(b.strchr('e'));
PRINT(b.strcat("There"));

auto c = ufcs('x');
PRINT(c);
PRINT(c.isalpha());
PRINT(c.ispunct());
PRINT(c.isdigit());
PRINT(c.toupper());

}

---

Compilation...

g++ -Wall ufcs.cpp -o ufcs

---

Output...

./ufcs
a: 1
a.sin(): 0.841471
a.sin().asin(): 1
a: 2.718
a.log(): 0.999896
a.log().exp(): 2.718
This
is
a
test
b: Hello
b.strstr("l"): llo
b.strchr('e'): ello
b.strcat("There"): HelloThere
c: x
c.isalpha(): 2
c.ispunct(): 0
c.isdigit(): 0
c.toupper(): 88

https://redd.it/1l1w6l0
@r_cpp
Can I put module declarations in header files?

Issue: https://github.com/Cvelth/vkfw/issues/19

So a while ago, I added module support to the vkfw library. It works fine for my usage with Clang, but recently (not really, it's been a while) GCC 15 released with module support finally stabilized. However, the way that module support is implemented is that in the header file vkfw.hpp, there is something like:

// ...
#ifdef VKFWMODULEIMPLEMENTATION
export module vkfw;
#endif
// ...

so that the vkfw.cpp file can be just:

module;
#define VKFWMODULEIMPLEMENTATION
#include <vkfw/vkfw.hpp>

However, GCC 15+ rejects compilation with

In file included from .../vkfw-src/include/vkfw/vkfw.cppm:3:
.../vkfw-src/include/vkfw/vkfw.hpp:219:8:
error: module control-line cannot be in included file

However, I can't find anywhere in the spec/cppreference that disallow this. So is this allowed at all, or it's just a GCC limitation?

https://redd.it/1lw2g0d
@r_cpp
Introducing Failsafe: A Modern C++ Error Handling and Logging Library

Hey r/cpp!

I'm excited to share Failsafe, a header-only C++ library that brings together modern error handling and logging with a focus on zero-overhead abstractions and developer experience.

# Why Another Error Handling Library?

While working on various C++ projects, I found myself repeatedly implementing similar patterns for error handling and logging. Existing solutions were either too heavyweight, required dependencies, or didn't provide the compile-time guarantees I wanted. Failsafe was born from the need for a lightweight, flexible solution that doesn't compromise on performance.

# Key Features

🚀 Zero-overhead abstractions \- Features can be completely compiled out when not needed
🔒 Thread-safe logging with compile-time level filtering
🛡️ Policy-based enforcement \- Inspired by Andrei Alexandrescu's enforcements
📍 Portable source location \- Works with C++20, compiler builtins, or traditional macros
🔧 C++17/20 compatible \- Adapts to your compiler's capabilities

# What Makes It Different?

# 1. Enforcement That Returns Values

// Traditional approach
void ptr = malloc(size);
if (!ptr) throw std::bad_alloc();

// With Failsafe - enforces AND returns the value
auto ptr = ENFORCE(malloc(size))("Allocation failed for size:", size);

# 2. Type-Safe Variadic Logging

// Builds messages efficiently without multiple string concatenations
LOG_ERROR("Network", "Connection failed:", error_code, "after", retry_count, "attempts");

// Conditional logging with zero overhead when disabled
LOG_DEBUG_IF(verbose, "Parser", "Token:", token, "at position:", pos);

# 3. Smart String Formatting

using namespace failsafe::detail;

// Automatic formatting for various types
auto msg = build_message("Address:", hex(0xDEADBEEF), "Time:", 100ms, "Path:", fs::path("/tmp"));

// Container formatting with limits
std::vector<int> data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
LOG_INFO("Data", "Values:", container(data, 5)); // Outputs: [1, 2, 3, 4, 5, ...]

# 4. Debug-Friendly Exception Handling

// Configure trap behavior for debugging
#define FAILSAFE_TRAP_MODE 1 // Trap to debugger, then throw

THROW_IF(result < 0, std::runtime_error, "Operation failed with code:", result);
// Breaks into debugger on failure, making debugging easier

# Performance First

Log statements below LOGGER_MIN_LEVEL are completely removed at compile time
No virtual function calls in the hot path
Header-only design allows full inlining and optimization
Thread safety can be disabled for single-threaded applications

# Real-World Example

Here's how it looks in practice:

#include <failsafe/logger.hh>
#include <failsafe/enforce.hh>
#include <failsafe/exception.hh>

class NetworkClient {
int socket_fd_ = -1;

public:
void connect(const std::string& host, int port) {
LOG_INFO("Network", "Connecting to", host, "port:", port);

// Enforce valid port range
ENFORCE_IN_RANGE(port, 1, 65535)("Invalid port number");

// Create socket with enforcement
socket_fd_ = ENFORCE(::socket(AF_INET, SOCK_STREAM, 0))
("Failed to create socket, errno:", errno);

// Conditional debug logging
LOG_DEBUG("Network", "Socket created with fd:", socket_fd_);

// ... rest of connection logic
}
};

# Backend Flexibility

The library supports multiple logging backends:

Built-in stderr backend with timestamps, thread IDs, and ANSI colors
POCO integration for existing POCO-based applications
gRPC/Abseil integration to capture gRPC's internal logs

# Get Started

It's header-only, so just copy the headers or use CMake:

include(FetchContent)
FetchContentDeclare(
failsafe
GIT
REPOSITORY https://github.com/yourusername/failsafe.git
)
Introducing Failsafe: A Modern C++ Error Handling and Logging Library

Hey r/cpp!

I'm excited to share **Failsafe**, a header-only C++ library that brings together modern error handling and logging with a focus on zero-overhead abstractions and developer experience.

# Why Another Error Handling Library?

While working on various C++ projects, I found myself repeatedly implementing similar patterns for error handling and logging. Existing solutions were either too heavyweight, required dependencies, or didn't provide the compile-time guarantees I wanted. Failsafe was born from the need for a lightweight, flexible solution that doesn't compromise on performance.

# Key Features

🚀 **Zero-overhead abstractions** \- Features can be completely compiled out when not needed
🔒 **Thread-safe logging** with compile-time level filtering
🛡️ **Policy-based enforcement** \- Inspired by Andrei Alexandrescu's enforcements
📍 **Portable source location** \- Works with C++20, compiler builtins, or traditional macros
🔧 **C++17/20 compatible** \- Adapts to your compiler's capabilities

# What Makes It Different?

# 1. Enforcement That Returns Values

// Traditional approach
void* ptr = malloc(size);
if (!ptr) throw std::bad_alloc();

// With Failsafe - enforces AND returns the value
auto ptr = ENFORCE(malloc(size))("Allocation failed for size:", size);

# 2. Type-Safe Variadic Logging

// Builds messages efficiently without multiple string concatenations
LOG_ERROR("Network", "Connection failed:", error_code, "after", retry_count, "attempts");

// Conditional logging with zero overhead when disabled
LOG_DEBUG_IF(verbose, "Parser", "Token:", token, "at position:", pos);

# 3. Smart String Formatting

using namespace failsafe::detail;

// Automatic formatting for various types
auto msg = build_message("Address:", hex(0xDEADBEEF), "Time:", 100ms, "Path:", fs::path("/tmp"));

// Container formatting with limits
std::vector<int> data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
LOG_INFO("Data", "Values:", container(data, 5)); // Outputs: [1, 2, 3, 4, 5, ...]

# 4. Debug-Friendly Exception Handling

// Configure trap behavior for debugging
#define FAILSAFE_TRAP_MODE 1 // Trap to debugger, then throw

THROW_IF(result < 0, std::runtime_error, "Operation failed with code:", result);
// Breaks into debugger on failure, making debugging easier

# Performance First

* Log statements below `LOGGER_MIN_LEVEL` are **completely removed** at compile time
* No virtual function calls in the hot path
* Header-only design allows full inlining and optimization
* Thread safety can be disabled for single-threaded applications

# Real-World Example

Here's how it looks in practice:

#include <failsafe/logger.hh>
#include <failsafe/enforce.hh>
#include <failsafe/exception.hh>

class NetworkClient {
int socket_fd_ = -1;

public:
void connect(const std::string& host, int port) {
LOG_INFO("Network", "Connecting to", host, "port:", port);

// Enforce valid port range
ENFORCE_IN_RANGE(port, 1, 65535)("Invalid port number");

// Create socket with enforcement
socket_fd_ = ENFORCE(::socket(AF_INET, SOCK_STREAM, 0))
("Failed to create socket, errno:", errno);

// Conditional debug logging
LOG_DEBUG("Network", "Socket created with fd:", socket_fd_);

// ... rest of connection logic
}
};

# Backend Flexibility

The library supports multiple logging backends:

* **Built-in stderr backend** with timestamps, thread IDs, and ANSI colors
* **POCO integration** for existing POCO-based applications
* **gRPC/Abseil integration** to capture gRPC's internal logs

# Get Started

It's header-only, so just copy the headers or use CMake:

include(FetchContent)
FetchContent_Declare(
failsafe
GIT_REPOSITORY https://github.com/yourusername/failsafe.git
)
Codegen: best way to multiply by 15

Should be simple enough but no compiler seem to agree, at least on x64:
https://godbolt.org/z/9fd8K5dqr
A bit better on arm64:
https://godbolt.org/z/zKaoMbexb

Not 100% sure which version is the fastest, but GCC "shift then sub" looks the simplest (with theoretically lower latency then "imul").
What's a bit sad is that they tend to go out of their way to impose their optimization, even when we explicitly write it as shift then sub.
Is there a way to force it anyway?

https://redd.it/1mp86lk
@r_cpp
Can someone explain this

So im doing Socket programing in C using winsoc2 and im donw with my server-socket now im programing my client-socket but i dont get this :

\#define DEFAULT_PORT "27015"



// Resolve the server address and port

iResult = getaddrinfo(argv[1\], DEFAULT_PORT, &hints, &result);

if (iResult != 0) {

printf("getaddrinfo failed: %d\\n", iResult);

WSACleanup();

return 1;

}

https://redd.it/1nx5arl
@r_cpp
ECS Implementation

Heyya reddit, i am making a game engine as a hobby and i was wondering if anyone would like to give some feedback on my ECS implementation. (I haven't measured it so idk about performance.)

What i want to know is that if this is a "correct" way to implement such a thing.

Thank you for the feedback.

#ifndef IKK_ECS_HPP
#define IKK_ECS_HPP


#include <unordered_map>
#include <algorithm>
#include <expected>
#include <vector>


#include "InariKonKon/Utility/NonConstructible.hpp"
#include "InariKonKon/ECS/Entities/Entity.hpp"
#include "InariKonKon/ECS/Systems/System.hpp"
#include "InariKonKon/Utility/Error.hpp"


namespace ikk
{
class ECS final : public NonConstructible
{
public:
template<std::derived_from<Component> T>
static void addComponentToEntity(const Entity& entity, T&& component) noexcept;


template<std::derived_from<Component> T>
static void removeComponentFromEntity(const Entity& entity) noexcept;


template<std::derived_from<Component> T>
[[nodiscard]] static std::expected<T*, Error> getComponentForEntity(const Entity& entity) noexcept;


template<std::derived_from<Component> T>
[[nodiscard]] static const std::vector<T> getComponents() noexcept;


template<std::derived_from<Component> T>
[[nodiscard]] static const std::vector<Entity> getEntitiesWith() noexcept;


template<DerivedFromSystem T>
static void applySystemOnEntity(const Entity& entity) noexcept;
private:
template<std::derived_from<Component> T>
[[nodiscard]] static std::unordered_map<Entity, T>& getComponentMap();
};


template<std::derived_from<Component> T>
void ECS::addComponentToEntity(const Entity& entity, T&& component) noexcept
{
std::unordered_map<Entity, T>& map = getComponentMap<T>();
if (map.contains(entity) == false)
map.emplace(entity, std::move(component));
}


template<std::derived_from<Component> T>
void ECS::removeComponentFromEntity(const Entity& entity) noexcept
{
std::unordered_map<Entity, T>& map = getComponentMap<T>();
if (map.contains(entity))
map.erase(entity);
}


template<std::derived_from<Component> T>
std::expected<T*, Error> ECS::getComponentForEntity(const Entity& entity) noexcept
{
std::unordered_map<Entity, T>& map = getComponentMap<T>();
if (map.contains(entity) == false)
return std::unexpected(Error{ "Entity does not have the requested component." });
else
return std::expected<T*, Error>{ &map.at(entity) };
}


template<std::derived_from<Component> T>
const std::vector<T> ECS::getComponents() noexcept
{
const std::unordered_map<Entity, T>& map = getComponentMap<T>();
std::vector<T> values{};
values.reserve(map.size());
std::transform(map.cbegin(), map.cend(), std::back_inserter(values),
[](const std::pair<Entity, T>& pair){ return pair.second; });
return values;
}


template<std::derived_from<Component> T>
const std::vector<Entity> ECS::getEntitiesWith() noexcept
{

const std::unordered_map<Entity, T>& map = getComponentMap<T>();
std::vector<Entity> values{};
values.reserve(map.size());
std::transform(map.cbegin(), map.cend(), std::back_inserter(values),
[](const std::pair<Entity, T>& pair){ return pair.first; });
return values;
}


template<DerivedFromSystem T>
void ECS::applySystemOnEntity(const Entity& entity) noexcept
{
std::expected<typename
Is this a correct implementation of Rust's Result enum for Arduino's C++ environment?

Hello Reddit!

Previously, I tried to recreate Rust's `Result` enum in C++ for the ESP32.

https://old.reddit.com/r/cpp/comments/1aifn5o/recreating_the_rust_result_enum_in_c_on_an_esp32/

But I have since realized that my old version kinda sucked!

For context, Arduino doesn't support most of the C++ standard library, but the ESP32 does.

What I really wanted was something you could just paste into the Arduino IDE and it would just work.
Now that I've rewritten it, it's possible!


However, I'm kind of sad to admit that I used AI (Google Gemini) to code a lot of this. Specifically:

* the [`std::remove_reference`], [`std::move`], and [`std::declval`] alternatives

* the [`auto`] and [`declval`] type shenanigans on the [`Result::match`], [`Result::map`] methods to get them to support lambdas. My original version only supported function pointers (see the code in the link above)!

* the other overloads of [`expect`] (I understand that `&` is a reference and `&&` is an rvalue reference (which is a basically thing that can be [`move`]d from?), but I still don't have quite the deep knowledge on it to write all the proper overloads, especially with those being after the function signature?)

* the improved versions of the [`Result`] type's copy and move constructors and its assignment operators (I didn't know about placement new before trying to rewrite the [`Result`] type, and it completely slipped my mind that you had to call the destructor if the [`other`] in the assignment operator was of a different tag!)

Of course, I've read through the code that the AI wrote and it seems logically correct to me, and I've rewritten a lot of it so that it's in my own coding style.

But because I've written it with AI, I don't really trust it.

Could I ask for you guys' help?
I'm only a beginner-intermediate C++ coder,
so is there anything wrong with the code that I don't see?

Thanks in advance!

```

#ifndef RESULT_HPP
#define RESULT_HPP

#include <new>

template<typename P>
void println(P printable);

[[noreturn]] void never() noexcept {
while (true) {
}
}

template <typename M>
[[noreturn]] void panic(M message) noexcept {
println(message);
never();
}

template<typename T> struct remove_reference {
using type = T;
};
template<typename T> struct remove_reference<T &> {
using type = T;
};
template<typename T> struct remove_reference< T && > {
using type = T;
};

template<typename T>
constexpr typename remove_reference<T>::type &&move(T &&arg) noexcept {
return static_cast< typename remove_reference<T>::type && >(arg);
}

template<typename T>
typename remove_reference<T>::type &&declval() noexcept;

template<typename T, typename E>
class Result {
private:
struct OkOverload {
};
struct ErrOverload {
};

public:
static Result ok(const T &ok) {
return Result{
Tag::Ok,
ok,
OkOverload{}
};
}

static Result ok(T &&ok) {
return Result{
Tag::Ok,
move(ok),
OkOverload{}
};
}

static Result err(const E &error) {
return Result{
Tag::Err,
error,
ErrOverload{}
};
}

static Result err(E &&error) {
return Result{
Tag::Err,
move(error),
ErrOverload{}
};
}

template<typename OnOk, typename OnErr>
auto match(OnOk on_ok, OnErr on_err) && -> decltype(on_ok(declval<T>())) {
switch (_tag) {
case Tag::Ok:
return on_ok(move(_value.ok));
case Tag::Err:
return on_err(move(_value.error));
default:
panic("[_tag] was left in an invalid state!");
}
}

template<typename OnOk, typename OnErr>
auto match(OnOk on_ok, OnErr on_err) const & -> decltype(on_ok(declval<const T &>()))
I am getting compilation error for my old cpp source code in new build envrionment

#define blahblah(SWC_MAJOR_VER, SWC_MINOR_VER) \

{ \

Dt_RECORD_SWC_Identification vSWCinfo = \

{ .DeSWCVersion = { .DeMajor = (SWC_MAJOR_VER), .DeMinor = (SWC_MINOR_VER) }, \

}; \

}



error: expected primary-expression before ‘)’ token .DeSWCVersion = { .DeMajor = (SWC_MAJOR_VER), .DeMinor = (SWC_MINOR_VER) }, \







co-pilot suggested code

#define blahblah(SWC_MAJOR_VER, SWC_MINOR_VER) \

{ \

Dt_RECORD_SWC_Identification vSWCinfo = \

{ { (SWC_MAJOR_VER), (SWC_MINOR_VER) } }; \

}


I am getting compilation error if i use this working code in new build environ ment and i f i use co piot suggested code my build is compiling in new build enviroement

https://redd.it/1p1zaaa
@r_cpp
C++ COMPLETE roadmap for study

Hi everyone

I asked chat gpt to create a COMPLETE roadmap of C++ so i wanted to know if its really good and COMPLETE.

Thats he send:

# C++ ULTRA-COMPLETE – Ultimate Roadmap



# Level 1 – Language Fundamentals

# 1. Data Types

1.1 Primitive types: int, float, double, char, bool
1.2 Modifiers: signed, unsigned, short, long
1.3 Constants and literals: const, constexpr, #define
1.4 Derived types: arrays, pointers, references
1.5 Special types: void, nullptr, auto, decltype
1.6 Structs and unions
1.7 Enumerations: enum, enum class
1.8 typedef and using
1.9 Advanced literals: binary (0b1010), digit separators (1'000'000)
1.10 Character types and strings (char, wchar_t, char16_t, char32_t)



# 2. Operators

2.1 Arithmetic: +, -, *, /, %, ++, --
2.2 Relational: ==, !=, <, >, <=, >=
2.3 Logical: &&, ||, !
2.4 Bitwise: &, |, ^, ~, <<, >>
2.5 Assignment: =, +=, -=, *=, /=, %=
2.6 Increment/decrement prefix/postfix
2.7 Ternary operator ?:
2.8 Comma operator ,
2.9 Pointer operators: *, &, ->
2.10 Casts: static_cast, dynamic_cast, reinterpret_cast, const_cast
2.11 Memory-related operators: sizeof, alignof
2.12 Rare operators: .*, ->*



# 3. Control Flow

3.1 Conditionals: if, else if, else, switch
3.2 Loops: for, while, do-while
3.3 Flow control: break, continue, return, goto
3.4 Exceptions: try, catch, throw
3.5 Rare/legacy: setjmp / longjmp (C legacy)



# 4. Functions

4.1 Declaration and definition
4.2 void and return-value functions
4.3 Pass-by-value, pass-by-reference, pointers
4.4 Default parameters
4.5 Function overloading
4.6 Inline and recursive functions
4.7 Lambda expressions (C++11+)
4.8 Anonymous functions capturing variables
4.9 Functions returning pointers and references
4.10 Virtual, pure, and abstract functions (OOP)
4.11 Function templates and template specialization
4.12 Variadic functions (...) and variadic templates
4.13 constexpr, consteval, and constinit functions



# Level 2 – Pointers, Memory, and Data Structures

# 5. Pointers and References

5.1 Pointer concept and operators * and &
5.2 Pointer-to-pointer
5.3 Constant pointers and pointers to constants
5.4 Function pointers
5.5 Object pointers
5.6 Simple and constant references
5.7 R-value references (&&)
5.8 Smart pointers: unique_ptr, shared_ptr, weak_ptr, auto_ptr (deprecated)
5.9 Pointers and multidimensional arrays
5.10 Pointer-to-member (int Class::* ptr)



# 6. Dynamic Memory Allocation

6.1 new and delete
6.2 Dynamic arrays (new[], delete[])
6.3 Dynamically allocated objects
6.4 Pointers to objects and arrays of objects
6.5 Memory management and leaks
6.6 RAII (Resource Acquisition Is Initialization)
6.7 Custom allocators (std::allocator)
6.8 Placement new
6.9 Aligned allocation (alignas)



# 7. Data Structures

7.1 Arrays and matrices
7.2 Strings (char[], std::string, std::wstring)
7.3 Structs, unions, enumerations
7.4 Singly and doubly linked lists
7.5 Stacks, queues, and priority queues
7.6 Vectors (std::vector)
7.7 Deques (std::deque)
7.8 Maps (std::map, std::unordered_map)
7.9 Sets (std::set, std::unordered_set)
7.10 Tuples (std::tuple) and pairs (std::pair)
7.11 Iterators and iterator adapters
7.12 STL algorithms (sort, find, for_each, etc.)



# Level 3 – Object-Oriented Programming (OOP)

# 8. Basic Concepts

8.1 Classes and objects
8.2 Encapsulation (public, private, protected)
8.3 Constructors and destructors
8.4 Default, parameterized, and copy constructors
8.5 Member initialization (initializer lists)
8.6 Methods: const, static, overloading



# 9. Inheritance and Polymorphism

9.1 Single and multiple inheritance
9.2 Access specifiers: public, protected, private
9.3 Static polymorphism (overloading)
9.4 Dynamic
what do you think about this

\#include <iostream>



\#define print(x) std::cout << x;



int main() {

char x[\] = " hello";

print("im dave," << x)



return 0;

}


can this be a problem?

https://redd.it/1p9owjg
@r_cpp
Jubi - Lightweight 2D Physics Engine

Jubi is a passion project I've been creating for around the past month, which is meant to be a lightweight physics engine, targeted for 2D. As of this post, it's on v0.2.1, with world creation, per-body integration, built-in error detection, force-based physics, and other basic needs for a physics engine.

Jubi has been intended for C/C++ projects, with C99 & C++98 as the standards. I've been working on it by myself, since around late-November, early-December. It has started from a basic single-header library to just create worlds/bodies and do raw-collision checks manually, to as of the current version, being able to handle hundreds of bodies with little to no slow down, even without narrow/broadphase implemented yet. Due to Jubi currently using o(n²) to check objects, compilation time can stack fast if used for larger scaled projects, limiting the max bodies at the minute to 1028.

It's main goal is to be extremely easy, and lightweight to use. With tests done, translated as close as I could to 1:1 replicas in Box2D & Chipmunk2D, Jubi has performed the fastest, with the least amount of LOC and boilerplate required for the same tests. We hope, by Jubi-1.0.0, to be near the level of usage/fame as Box2D and/or Chipmunk2D.

Jubi Samples:

#define JUBIIMPLEMENTATION
#include "../Jubi.h"

#include <stdio.h>

int main() {
    JubiWorld2D WORLD = Jubi
CreateWorld2D();

// JBody2DCreateBox(JubiWorld2D *WORLD, Vector2 Position, Vector2 Size, BodyType2D Type, float Mass)
    Body2D *Box = JBody2D
CreateBox(&WORLD, (Vector2){0, 0}, (Vector2){1, 1}, BODYDYNAMIC, 1.0f);
   
    // ~1 second at 60 FPS
    for (int i=0; i < 60; i++) {
        Jubi
StepWorld2D(&WORLD, 0.033f);

        printf("Frame: %02d | Position: (%.3f, %.3f) | Velocity: (%.3f, %.3f) | Index: %d\n", i, Box -> Position.x, Box -> Position.y, Box -> Velocity.x, Box -> Velocity.y, Box -> Index);
    }
   
    return 0;
}

Jubi runtime compared to other physic engines:

|Physics Engine|Runtime|
|:-|:-|
|Jubi|0.0036ms|
|Box2D|0.0237ms|
|Chipmunk2D|0.0146ms|

Jubi Github: https://github.com/Avery-Personal/Jubi

https://redd.it/1prwf8o
@r_cpp
MayaFlux 0.1.0: A Digital-Native Substrate for Multimedia Computation

Hello r/cpp folks,

I am very excited to announce the initial release of my new creative multimedia programming framework. Here is a short release text, you can find the full context on the [website](https://mayaflux.org/releases/)

MayaFlux 0.1.0 is a C++20/23 infrastructure built to replace the 1980s-era architectures still underlying modern creative coding tools. Built with 15 years of interdisciplinary practice and DSP engineering, it departs from the "analog metaphors" that have constrained digital creativity since the 1980s. MayaFlux does not simulate oscillators or patch cables; it processes unified numerical streams through lock-free computation graphs.

## The Death of Analog Metaphor

Traditional tools (DAWs, visual patchers) rely on legacy pedagogical metaphors. MayaFlux rejects these in favor of computational logic. In this framework, **audio, visuals, and control data are identical.** Every sample, pixel, and parameter is a double-precision floating-point number. This eliminates the artificial boundaries between domains. A single unit can output audio, trigger GPU compute shaders, and coordinate temporal events in the same processing callback without conversion overhead.

## Technical Core: Lock-Free & Deterministic

Building on C++20, MayaFlux utilizes `atomic_ref` and compare-exchange operations to ensure thread safety without mutexes. You can restructure complex graphs or inject new nodes while audio plays -> no glitches, no dropouts, and no contentions. The state promise ensures every node processes exactly once per cycle, regardless of how many consumers it has, enabling true multi-rate adaptation (Audio, Visual, and Custom rates) within a unified graph.

## Lila: Live C++ via LLVM JIT

One of MayaFlux's most transformative features is the **Lila JIT system**. Utilizing LLVM 21+, Lila allows for full C++20 syntax evaluation (including templates and `constexpr`) in real-time. There is no "application restart" or "compilation wait." You write C++ code, hit evaluate, and hear/see the results within one buffer cycle. Live coding no longer requires switching to a "simpler" interpreted language; you have the full power of the C++ compiler in the hot path.

## Graphics as First-Class Computation

Unlike tools where graphics are a "visualization" afterthought, MayaFlux treats the **Vulkan 1.3** pipeline with the same architectural rigor as audio DSP. The graphics pipeline shares the same lock-free buffer coordination and node-network logic. Whether you are driving vertex displacement via a recursive audio filter or mapping particle turbulence to a high-precision phasor, the data flow is seamless and low-level.

## Temporal Materiality

By utilizing **C++20 Coroutines**, MayaFlux turns Time into a compositional material. Through the `co_await` keyword, developers can suspend logic on sample counts, frame boundaries, or predicates. This eliminates "callback hell" and allows temporal logic to be written exactly how it is imagined: linearly and deterministically.

## Who is it for?

MayaFlux is infrastructure, not an application. It is for:

- **Creative Technologists** hitting the limits of Processing or Max/MSP.
- **Researchers** needing direct buffer access and novel algorithm implementation.
- **Developers** seeking low-level GPU/Audio control without framework-imposed boundaries.

The substrate is ready. Visit **mayaflux.org** to start sculpting data.

## A quick teaser

```cpp
#pragma once
#define MAYASIMPLE
#include "MayaFlux/MayaFlux.hpp"

void settings() {
// Low-latency audio setup
auto& stream = MayaFlux::Config::get_global_stream_info();
stream.sample_rate = 48000;
}

void compose() {

// 1. Create the bell
auto bell = vega.ModalNetwork(
12,
220.0,
ModalNetwork::Spectrum::INHARMONIC)[0]
| Audio;

// 2. Create audio-driven logic
auto source_sine = vega.Sine(0.2, 1.0f); // 0.2 Hz slow oscillator

static double last_input = 0.0;
auto
MayaFlux 0.1.0: A Digital-Native Substrate for Multimedia Computation

Hello r/cpp folks,

I am very excited to announce the initial release of my new creative multimedia programming framework. Here is a short release text, you can find the full context on the [website](https://mayaflux.org/releases/) or the [git repo](https://github.com/MayaFlux/MayaFlux)

MayaFlux 0.1.0 is a C++20/23 infrastructure built to replace the 1980s-era architectures still underlying modern creative coding tools. Built with 15 years of interdisciplinary practice and DSP engineering, it departs from the "analog metaphors" that have constrained digital creativity since the 1980s. MayaFlux does not simulate oscillators or patch cables; it processes unified numerical streams through lock-free computation graphs.

# The Death of Analog Metaphor

Traditional tools (DAWs, visual patchers) rely on legacy pedagogical metaphors. MayaFlux rejects these in favor of computational logic. In this framework, **audio, visuals, and control data are identical.** Every sample, pixel, and parameter is a double-precision floating-point number. This eliminates the artificial boundaries between domains. A single unit can output audio, trigger GPU compute shaders, and coordinate temporal events in the same processing callback without conversion overhead.

# Technical Core: Lock-Free & Deterministic

Building on C++20, MayaFlux utilizes `atomic_ref` and compare-exchange operations to ensure thread safety without mutexes. You can restructure complex graphs or inject new nodes while audio plays -> no glitches, no dropouts, and no contentions. The state promise ensures every node processes exactly once per cycle, regardless of how many consumers it has, enabling true multi-rate adaptation (Audio, Visual, and Custom rates) within a unified graph.

# Lila: Live C++ via LLVM JIT

One of MayaFlux's most transformative features is the **Lila JIT system**. Utilizing LLVM 21+, Lila allows for full C++20 syntax evaluation (including templates and `constexpr`) in real-time. There is no "application restart" or "compilation wait." You write C++ code, hit evaluate, and hear/see the results within one buffer cycle. Live coding no longer requires switching to a "simpler" interpreted language; you have the full power of the C++ compiler in the hot path.

# Graphics as First-Class Computation

Unlike tools where graphics are a "visualization" afterthought, MayaFlux treats the **Vulkan 1.3** pipeline with the same architectural rigor as audio DSP. The graphics pipeline shares the same lock-free buffer coordination and node-network logic. Whether you are driving vertex displacement via a recursive audio filter or mapping particle turbulence to a high-precision phasor, the data flow is seamless and low-level.

# Temporal Materiality

By utilizing **C++20 Coroutines**, MayaFlux turns Time into a compositional material. Through the `co_await` keyword, developers can suspend logic on sample counts, frame boundaries, or predicates. This eliminates "callback hell" and allows temporal logic to be written exactly how it is imagined: linearly and deterministically.

# Who is it for?

MayaFlux is infrastructure, not an application. It is for:

* **Creative Technologists** hitting the limits of Processing or Max/MSP.
* **Researchers** needing direct buffer access and novel algorithm implementation.
* **Developers** seeking low-level GPU/Audio control without framework-imposed boundaries.

The substrate is ready. Visit **mayaflux.org** to start sculpting data.

# A quick teaser
```cpp
#pragma once
#define MAYASIMPLE
#include "MayaFlux/MayaFlux.hpp"

void settings() {
// Low-latency audio setup
auto& stream = MayaFlux::Config::get_global_stream_info();
stream.sample_rate = 48000;
}

void compose() {

// 1. Create the bell
auto bell = vega.ModalNetwork(
12,
220.0,
ModalNetwork::Spectrum::INHARMONIC)[0]
| Audio;

// 2. Create
"override members" idea as a gateway to UFCS (language evolution)

(UFCS backgrounder: https://isocpp.org/files/papers/N4174.pdf )

I have two functions that tell me if a string contains the
characters of a particular integer. They're called hasInt and intIn.
(intIn is inspired by the python keyword in.)
They looks like this:

bool hasInt(const string s, int n)// does s have n?
{
return s.contains(tostring(n));
}

bool intIn(int n, const string s)// is n in s?
{
return s.contains(to
string(n));
}

It would be convenient if I could add hasInt as a member function to std::string:

bool string::hasInt(int n)
{
return ::hasInt(this, n);
}

Then I could use "member syntax" to call the function, like `text.hasInt(123)`.

Of course, that's not possible, because then I'd be changing the header files
in the standard libraries.

Here's an idea for a new language feature:
let's use the `override` keyword to allow us to "inject" member functions
into an existing class, without modifying the class definition. So the code:

override bool string::hasInt(int n)
{
return ::hasInt(
this, n);
}

will (in effect) add hasInt as a member function to string.

Thus, this "override member function" feature has a syntax like:

ReturnType ClassName::function(args){...etc...}

HOWEVER..... what if ClassName doesn't necessarily need to be a class, and could be
other types? Then you open the door to override members like:

override bool int::intIn(const string s)
{
return ::intIn(this, s);
}

Which allows code like `(123).intIn(text)`.

This is halfway to UFCS!

Using some macro magic and helper templates, we could
define a
MAKE_UFCS macro to convert a non-member function into a member function:

#define MAKE_UFCS(f) \
override \
retType(f) argType1(f)::f(argType2(f) x)\
{ \
return f(
this, x); \
}

Thus the non-member functions hasInt and intIn could be "opted in" to UFCS
by the macro calls:

MAKEUFCS(hasInt);
MAKE
UFCS(intIn);

Or maybe, if this override-to-UFCS is useful enough, the override feature can be
applied to a collection of functions at once, like:

override hasInt, intIn;

or

override {
#include <cstdlib>
}

To UFCS-ify an entire header file at the same time.

EDIT: this idea would be similar to Scala's "Extension Methods": https://docs.scala-lang.org/scala3/book/ca-extension-methods.html

or C#'s "Extension Members": https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods

https://redd.it/1qyikcg
@r_cpp