Proposal for testing global functions
I am writing tests for an embedded project and found myself wondering why testing global / static or free functions is so controversial and why it would have to contain expensive trickery with the linker or other parts of the compiler in order to achieve them ([related stackoverflow post](https://stackoverflow.com/questions/28392277/mocking-free-function)).
This is why wanted to share my approach on this which is based on:
* some sort of \`typeid\` method ([with no rtti for embedded](https://stackoverflow.com/questions/8001207/compile-time-typeid-without-rtti-with-gcc))
* a mapping of function pointers (used unordered\_map here for simplicity)
* a macro-based check in every mocked function with some sort of call-forwarding
The drawback with this method is obviously the last point which requires that every function you want to mock out has to have this check at the beginning, and the need to have a globally available mocking repository. Its a POC at best and I'm looking for ways on how to improve it further. Thoughts about the usefulness of this approach in larger projects?
#pragma once
#include <unordered_map>
#ifndef __TEST__
#define ADD_MOCK(FOO, MOCK)
#define CLEAR_MOCK(FOO)
#define CLEAR_MOCKS()
#define CHECK_MOCK(FOO, ...)
#else
#define ADD_MOCK(FOO, MOCK) Mocks::add(FOO, MOCK)
#define CLEAR_MOCK(FOO) Mocks::remove(FOO)
#define CLEAR_MOCKS() Mocks::clear()
#define CHECK_MOCK(FOO, ...) \
do { \
auto _mock = Mocks::get(FOO); \
if (!_mock) break; \
return _mock(__VA_ARGS__); \
} while (0)
template <class T>
size_t typeidNoRtti(__attribute__((unused)) const T value = nullptr) {
static T *marker = NULL;
return (size_t)▮
}
namespace Mocks
{
struct MockFn {
void *mock;
size_t type;
};
extern std::unordered_map<void *, MockFn> _mocks;
template <typename T>
static inline void add(const T &fn, const T &mock) {
_mocks.insert(std::make_pair((void *)fn, MockFn{(void *)mock, typeidNoRtti(fn)}));
}
template <typename T>
static inline void remove(const T &fn) { _mocks.erase((void *)fn); }
static inline void clear() { _mocks.clear(); }
template <typename T>
static inline T *get(const T &fn) {
if (!_mocks.count((void *)fn)) return nullptr;
const auto &mock = _mocks.at((void *)fn);
if (typeidNoRtti(fn) != mock.type) return nullptr;
return (T *)mock.mock;
}
};
#endif
Usage:
#include "test.hpp"
static int8_t foo(int8_t a) {
CHECK_MOCK(foo, a);
return a;
}
static int8_t foo_mock(int8_t a) { return -a; }
static int bar(int a) { return 10 * a; }
UNIT_TEST(Mock, Basic) {
ADD_MOCK(foo, foo_mock);
EXPECT_EQ(Mocks::get(foo), foo_mock);
EXPECT_EQ(Mocks::get(bar), nullptr);
EXPECT_EQ(Mocks::get((void *)foo), nullptr);
EXPECT_EQ(foo(1), -1);
CLEAR_MOCK(foo);
EXPECT_EQ(Mocks::get(foo), nullptr);
EXPECT_EQ(foo(1), 1);
}
https://redd.it/1fqlb4c
@r_cpp
I am writing tests for an embedded project and found myself wondering why testing global / static or free functions is so controversial and why it would have to contain expensive trickery with the linker or other parts of the compiler in order to achieve them ([related stackoverflow post](https://stackoverflow.com/questions/28392277/mocking-free-function)).
This is why wanted to share my approach on this which is based on:
* some sort of \`typeid\` method ([with no rtti for embedded](https://stackoverflow.com/questions/8001207/compile-time-typeid-without-rtti-with-gcc))
* a mapping of function pointers (used unordered\_map here for simplicity)
* a macro-based check in every mocked function with some sort of call-forwarding
The drawback with this method is obviously the last point which requires that every function you want to mock out has to have this check at the beginning, and the need to have a globally available mocking repository. Its a POC at best and I'm looking for ways on how to improve it further. Thoughts about the usefulness of this approach in larger projects?
#pragma once
#include <unordered_map>
#ifndef __TEST__
#define ADD_MOCK(FOO, MOCK)
#define CLEAR_MOCK(FOO)
#define CLEAR_MOCKS()
#define CHECK_MOCK(FOO, ...)
#else
#define ADD_MOCK(FOO, MOCK) Mocks::add(FOO, MOCK)
#define CLEAR_MOCK(FOO) Mocks::remove(FOO)
#define CLEAR_MOCKS() Mocks::clear()
#define CHECK_MOCK(FOO, ...) \
do { \
auto _mock = Mocks::get(FOO); \
if (!_mock) break; \
return _mock(__VA_ARGS__); \
} while (0)
template <class T>
size_t typeidNoRtti(__attribute__((unused)) const T value = nullptr) {
static T *marker = NULL;
return (size_t)▮
}
namespace Mocks
{
struct MockFn {
void *mock;
size_t type;
};
extern std::unordered_map<void *, MockFn> _mocks;
template <typename T>
static inline void add(const T &fn, const T &mock) {
_mocks.insert(std::make_pair((void *)fn, MockFn{(void *)mock, typeidNoRtti(fn)}));
}
template <typename T>
static inline void remove(const T &fn) { _mocks.erase((void *)fn); }
static inline void clear() { _mocks.clear(); }
template <typename T>
static inline T *get(const T &fn) {
if (!_mocks.count((void *)fn)) return nullptr;
const auto &mock = _mocks.at((void *)fn);
if (typeidNoRtti(fn) != mock.type) return nullptr;
return (T *)mock.mock;
}
};
#endif
Usage:
#include "test.hpp"
static int8_t foo(int8_t a) {
CHECK_MOCK(foo, a);
return a;
}
static int8_t foo_mock(int8_t a) { return -a; }
static int bar(int a) { return 10 * a; }
UNIT_TEST(Mock, Basic) {
ADD_MOCK(foo, foo_mock);
EXPECT_EQ(Mocks::get(foo), foo_mock);
EXPECT_EQ(Mocks::get(bar), nullptr);
EXPECT_EQ(Mocks::get((void *)foo), nullptr);
EXPECT_EQ(foo(1), -1);
CLEAR_MOCK(foo);
EXPECT_EQ(Mocks::get(foo), nullptr);
EXPECT_EQ(foo(1), 1);
}
https://redd.it/1fqlb4c
@r_cpp
Stack Overflow
Mocking free function
I am stuck in a problem and can't seem to find the solution.
I am using VS2005 SP1 for compiling the code.
I have a global function:
A* foo();
I have a mock class
class MockA : public A {
publ...
I am using VS2005 SP1 for compiling the code.
I have a global function:
A* foo();
I have a mock class
class MockA : public A {
publ...
Efficient Softmax jacobian and gradient algorithms
I am writing a function in C++, for the task of using the output of the Softmax() function, and calculating the jacobians before using them to calculate the gradients of the output W.R.T. the Softmax input. Normally, this would be a relatively straightforward task, but I am working with an architecture that uses tensor data. the function must be adaptive enough to handle input data(the output of the Softmax function) of any shape, where Softmax() was applied along any dimension. I have made a version that works, but it is extremely slow, and I need a faster method. Here is my current function:
static void softmaxJacobian(const float* x, float* y, const float* outputGrad, const int dimension, const int* shape, const int jSize, const int dataSize, const int blockStride) {
using namespace std::chrono;
int numBlocks = dataSize / jSize;
// Allocate memory once outside the loop
float* jacobian = new float[jSize * jSize];
auto start = high_resolution_clock::now();
// Parallelize over blocks, and use thread-private arrays for slices
#pragma omp parallel
{
float* slice = new float[jSize];
float* outputSlice = new float[jSize];
#pragma omp for
for (int blockIndex = 0; blockIndex < numBlocks; blockIndex++) {
int blockStartIndex = (blockIndex / blockStride) * (blockStride * jSize) + (blockIndex % blockStride);
// Efficiently extract data for the current block
for (int i = 0; i < jSize; i++) {
int index = blockStartIndex + i * blockStride;
slice[i] = x[index];
outputSlice[i] = outputGrad[index];
}
// Construct the Jacobian matrix (optimize for diagonal and off-diagonal)
for (int i = 0; i < jSize; i++) {
for (int j = 0; j < jSize; j++) {
jacobian[i * jSize + j] = (i == j) ? slice[i] * (1 - slice[i]) : -(slice[i] * slice[j]);
}
}
// Perform matrix-vector multiplication (Jacobian * outputSlice)
for (int i = 0; i < jSize; i++) {
float sum = 0.0f;
for (int j = 0; j < jSize; j++) {
sum += jacobian[i * jSize + j] * outputSlice[j];
}
int index = blockStartIndex + i * blockStride;
y[index] = sum; // Write the result back
}
}
// Cleanup thread-local memory
delete[] slice;
delete[] outputSlice;
}
auto end = high_resolution_clock::now();
std::cout << "Total time for function: " << duration_cast<milliseconds>(end - start).count() << " ms\n";
// Cleanup
delete[] jacobian;
}
Any suggestions on improved algorithms?
https://redd.it/1g5i8m8
@r_cpp
I am writing a function in C++, for the task of using the output of the Softmax() function, and calculating the jacobians before using them to calculate the gradients of the output W.R.T. the Softmax input. Normally, this would be a relatively straightforward task, but I am working with an architecture that uses tensor data. the function must be adaptive enough to handle input data(the output of the Softmax function) of any shape, where Softmax() was applied along any dimension. I have made a version that works, but it is extremely slow, and I need a faster method. Here is my current function:
static void softmaxJacobian(const float* x, float* y, const float* outputGrad, const int dimension, const int* shape, const int jSize, const int dataSize, const int blockStride) {
using namespace std::chrono;
int numBlocks = dataSize / jSize;
// Allocate memory once outside the loop
float* jacobian = new float[jSize * jSize];
auto start = high_resolution_clock::now();
// Parallelize over blocks, and use thread-private arrays for slices
#pragma omp parallel
{
float* slice = new float[jSize];
float* outputSlice = new float[jSize];
#pragma omp for
for (int blockIndex = 0; blockIndex < numBlocks; blockIndex++) {
int blockStartIndex = (blockIndex / blockStride) * (blockStride * jSize) + (blockIndex % blockStride);
// Efficiently extract data for the current block
for (int i = 0; i < jSize; i++) {
int index = blockStartIndex + i * blockStride;
slice[i] = x[index];
outputSlice[i] = outputGrad[index];
}
// Construct the Jacobian matrix (optimize for diagonal and off-diagonal)
for (int i = 0; i < jSize; i++) {
for (int j = 0; j < jSize; j++) {
jacobian[i * jSize + j] = (i == j) ? slice[i] * (1 - slice[i]) : -(slice[i] * slice[j]);
}
}
// Perform matrix-vector multiplication (Jacobian * outputSlice)
for (int i = 0; i < jSize; i++) {
float sum = 0.0f;
for (int j = 0; j < jSize; j++) {
sum += jacobian[i * jSize + j] * outputSlice[j];
}
int index = blockStartIndex + i * blockStride;
y[index] = sum; // Write the result back
}
}
// Cleanup thread-local memory
delete[] slice;
delete[] outputSlice;
}
auto end = high_resolution_clock::now();
std::cout << "Total time for function: " << duration_cast<milliseconds>(end - start).count() << " ms\n";
// Cleanup
delete[] jacobian;
}
Any suggestions on improved algorithms?
https://redd.it/1g5i8m8
@r_cpp
Reddit
From the cpp community on Reddit
Explore this post and more from the cpp community
ImGui::NewFrame() throwing an error after second call
The error is: "abort() has been called"
This is the code:
`//io.ConfigFlags`
https://redd.it/1harvjb
@r_cpp
The error is: "abort() has been called"
This is the code:
#include <enet/enet.h>#include <glad/glad.h>#include <GLFW/glfw3.h>#include <stb_image/stb_image.h>#include <stb_truetype/stb_truetype.h>#include "gl2d/gl2d.h"#include <iostream>#include <ctime>#include "platformTools.h"#include <raudio.h>#include "platformInput.h"#include "otherPlatformFunctions.h"#include "gameLayer.h"#include <fstream>#include <chrono>#include "errorReporting.h"#include "imgui.h"#include "backends/imgui_impl_glfw.h"#include "backends/imgui_impl_opengl3.h"#include "imguiThemes.h"#ifdef _WIN32#include <Windows.h>#endif#undef min#undef maxint main(){GLFWwindow* window;#pragma region window and openglpermaAssertComment(glfwInit(), "err initializing glfw");glfwWindowHint(GLFW_SAMPLES, 4);#ifdef __APPLE__glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, 1);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);#endifint w = 500;int h = 500;window = glfwCreateWindow(w, h, "Window", nullptr, nullptr);glfwMakeContextCurrent(window);glfwSwapInterval(1);//permaAssertComment(gladLoadGL(), "err initializing glad");permaAssertComment(gladLoadGLLoader((GLADloadproc)glfwGetProcAddress), "err initializing glad");#pragma endregion#pragma region gl2dgl2d::init();#pragma endregion#pragma region imguiImGui::CreateContext();imguiThemes::embraceTheDarkness();ImGuiIO& io = ImGui::GetIO(); (void)io;io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;`//io.ConfigFlags`
|= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controlsio.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Dockingio.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform WindowsImGuiStyle& style = ImGui::GetStyle();if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable){style.Colors[ImGuiCol_WindowBg].w = 0.f;style.Colors[ImGuiCol_DockingEmptyBg].w = 0.f;}ImGui_ImplGlfw_InitForOpenGL(window, true);ImGui_ImplOpenGL3_Init("#version 330");#pragma endregionwhile (!glfwWindowShouldClose(window)){glfwPollEvents();ImGui_ImplOpenGL3_NewFrame();ImGui_ImplGlfw_NewFrame();glClearColor(0.0f, 0.0f, 0.0f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);ImGui::NewFrame();ImGui::Begin("My Scene");ImGui::End();ImGui::Render();ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());glfwSwapBuffers(window);}}https://redd.it/1harvjb
@r_cpp
Reddit
From the cpp community on Reddit
Explore this post and more from the cpp community
Can I put import inside the global module fragment?
So I am working on importizer that automatically create a module from a header file. It does so by collecting preprocessor directives, especially conditional ones, that has a #include inside and recreate it on top. For example:
// File.h
#pragma once
#ifdef COND
#include <vector>
#include <modularizedHeader.h>
#endif
will create this preamble
module;
#ifdef COND
#include <vector>
#endif
export module File;
#ifdef COND
import modularizedHeader;
#endif
which repeats the condition twice. With more complex conditions, the length will very quickly get out of hand.
Can I put import in the GMF like this to save some space?
module;
#ifdef COND
#include <vector>
import modularizedHeader;
#endif
export module File;
I was suspicious at first so I tested this approach on Godbolt (try putting the import into the GMF), and it's fine. I even read the C++ standard for modules, and I don't see any regulation about their location. Moreover, on cppreference, only preprocessing directives can go into the GMF, and import does count as one.
Is there any problem with doing it like this, and is there a better way to repeat the condition only once?
https://redd.it/1ihbb9f
@r_cpp
So I am working on importizer that automatically create a module from a header file. It does so by collecting preprocessor directives, especially conditional ones, that has a #include inside and recreate it on top. For example:
// File.h
#pragma once
#ifdef COND
#include <vector>
#include <modularizedHeader.h>
#endif
will create this preamble
module;
#ifdef COND
#include <vector>
#endif
export module File;
#ifdef COND
import modularizedHeader;
#endif
which repeats the condition twice. With more complex conditions, the length will very quickly get out of hand.
Can I put import in the GMF like this to save some space?
module;
#ifdef COND
#include <vector>
import modularizedHeader;
#endif
export module File;
I was suspicious at first so I tested this approach on Godbolt (try putting the import into the GMF), and it's fine. I even read the C++ standard for modules, and I don't see any regulation about their location. Moreover, on cppreference, only preprocessing directives can go into the GMF, and import does count as one.
Is there any problem with doing it like this, and is there a better way to repeat the condition only once?
https://redd.it/1ihbb9f
@r_cpp
GitHub
GitHub - msqr1/importizer: Backward compatibly refactor header-based C++ into modules.
Backward compatibly refactor header-based C++ into modules. - msqr1/importizer
Inexplicable error when trying to intercept dll calls with a proxy
I am currently trying to modify an application called **EdingCNC**, which relies on a dynamic link library called `cncapi.dll` for its functionality. My goal is to **intercept calls** to the function`CncRunSingleLine` inside the DLL, modify the behavior if necessary, and then forward the call to the original function. All other functions are forwarded via `#pragma comment(linker, "/export:...=...,@...")`
The function signature (as defined in `cncapi.dll`) is:
`CNC_RC EXP2DF __stdcall CncRunSingleLine(char *text);`
# My Approach (Proxy DLL Implementation)
To intercept this function, I created a **proxy DLL** with the same export name. This DLL captures calls to `CncRunSingleLine`, executes some additional logic, and then calls the original function inside `cncapi.dll`. Here’s my current implementation:
#define C_DLL_EXPORT __declspec(dllexport) // or your defined macro if different
typedef CNC_RC(__stdcall* pfCncRunSingleLine)(char* text); // Correct function pointer type
extern "C" { // Ensures C-style linkage (no name mangling)
// Export the function with the correct return type (CNC_RC)
C_DLL_EXPORT CNC_RC CncRunSingleLine(char* text)
{
if (text == nullptr)
{
::MessageBoxW(NULL, L"Invalid input parameter: text is NULL", L"Error", MB_ICONERROR);
return CNC_RC_ERR; // Return error if the text parameter is invalid
}
// 1) Get the original DLL handle (adjust the DLL name if needed)
HMODULE hModule = ::GetModuleHandle(TEXT("_cncapi.dll")); // Adjust the DLL name if required
if (!hModule)
{
// Display error and return failure code if DLL is not found
::MessageBoxW(NULL, L"Failed to load the original CNC API DLL", L"Error", MB_ICONERROR);
return CNC_RC_ERR; // Return error code
}
// 2) Get the function address inside the original DLL
pfCncRunSingleLine pOriginalCncRunSingleLine = (pfCncRunSingleLine)::GetProcAddress(hModule, "CncRunSingleLine");
if (!pOriginalCncRunSingleLine)
{
// Display error and return failure code if function is not found
::MessageBoxW(NULL, L"Failed to find CncRunSingleLine function", L"Error", MB_ICONERROR);
return CNC_RC_ERR; // Return error code
}
// 3) Call the original function and return the result
CNC_RC result = pOriginalCncRunSingleLine(text); // Call the function
// Check if the result is valid
if (result != CNC_RC_OK) // Replace CNC_RC_OK with the correct successful return code if necessary
{
::MessageBoxW(NULL, L"CncRunSingleLine function call failed", L"Error", MB_ICONERROR);
}
return result; // Return the result from the original function
}
}
It crashes after "successfully executing" the fusddnction. The result i want to achive is made in the program but then it crashes right after.
# Problem
* The function executes successfully, meaning that the modification takes effect inside EdingCNC.
* However, immediately after execution, the application crashes.
* The crash happens after returning from CncRunSingleLine(), even though the expected result is achieved.
# What I Have Tried
* Verified that the intercepted function is indeed called, and its result matches the expected behavior.
* Checked the return value and confirmed that CncRunSingleLine completes execution before the crash.
* Confirmed that hModule correctly retrieves \_cncapi.dll and that the function pointer is valid.
* Used MessageBoxW() before and after the function call, confirming that the crash occurs after returning from CncRunSingleLine().
https://redd.it/1iwkp55
@r_cpp
I am currently trying to modify an application called **EdingCNC**, which relies on a dynamic link library called `cncapi.dll` for its functionality. My goal is to **intercept calls** to the function`CncRunSingleLine` inside the DLL, modify the behavior if necessary, and then forward the call to the original function. All other functions are forwarded via `#pragma comment(linker, "/export:...=...,@...")`
The function signature (as defined in `cncapi.dll`) is:
`CNC_RC EXP2DF __stdcall CncRunSingleLine(char *text);`
# My Approach (Proxy DLL Implementation)
To intercept this function, I created a **proxy DLL** with the same export name. This DLL captures calls to `CncRunSingleLine`, executes some additional logic, and then calls the original function inside `cncapi.dll`. Here’s my current implementation:
#define C_DLL_EXPORT __declspec(dllexport) // or your defined macro if different
typedef CNC_RC(__stdcall* pfCncRunSingleLine)(char* text); // Correct function pointer type
extern "C" { // Ensures C-style linkage (no name mangling)
// Export the function with the correct return type (CNC_RC)
C_DLL_EXPORT CNC_RC CncRunSingleLine(char* text)
{
if (text == nullptr)
{
::MessageBoxW(NULL, L"Invalid input parameter: text is NULL", L"Error", MB_ICONERROR);
return CNC_RC_ERR; // Return error if the text parameter is invalid
}
// 1) Get the original DLL handle (adjust the DLL name if needed)
HMODULE hModule = ::GetModuleHandle(TEXT("_cncapi.dll")); // Adjust the DLL name if required
if (!hModule)
{
// Display error and return failure code if DLL is not found
::MessageBoxW(NULL, L"Failed to load the original CNC API DLL", L"Error", MB_ICONERROR);
return CNC_RC_ERR; // Return error code
}
// 2) Get the function address inside the original DLL
pfCncRunSingleLine pOriginalCncRunSingleLine = (pfCncRunSingleLine)::GetProcAddress(hModule, "CncRunSingleLine");
if (!pOriginalCncRunSingleLine)
{
// Display error and return failure code if function is not found
::MessageBoxW(NULL, L"Failed to find CncRunSingleLine function", L"Error", MB_ICONERROR);
return CNC_RC_ERR; // Return error code
}
// 3) Call the original function and return the result
CNC_RC result = pOriginalCncRunSingleLine(text); // Call the function
// Check if the result is valid
if (result != CNC_RC_OK) // Replace CNC_RC_OK with the correct successful return code if necessary
{
::MessageBoxW(NULL, L"CncRunSingleLine function call failed", L"Error", MB_ICONERROR);
}
return result; // Return the result from the original function
}
}
It crashes after "successfully executing" the fusddnction. The result i want to achive is made in the program but then it crashes right after.
# Problem
* The function executes successfully, meaning that the modification takes effect inside EdingCNC.
* However, immediately after execution, the application crashes.
* The crash happens after returning from CncRunSingleLine(), even though the expected result is achieved.
# What I Have Tried
* Verified that the intercepted function is indeed called, and its result matches the expected behavior.
* Checked the return value and confirmed that CncRunSingleLine completes execution before the crash.
* Confirmed that hModule correctly retrieves \_cncapi.dll and that the function pointer is valid.
* Used MessageBoxW() before and after the function call, confirming that the crash occurs after returning from CncRunSingleLine().
https://redd.it/1iwkp55
@r_cpp
Reddit
From the cpp community on Reddit
Explore this post and more from the cpp community
Synthetisizing lightweight forward modules
I have ported the C++ sources of our [Windows application](https://www.cadifra.com/) from header files to using C++ 20 modules.
Our codebase is heavily using forward declarations for classes wherever possible.
The code is devided into ~40 packages. Every package uses a namespace and all the files of a package are part of a "Project" in Visual Studio.
Due to the strong [name attaching rules of C++20 modules](https://en.cppreference.com/w/cpp/language/modules#:~:text=In%20general%2C%20if,the%20same%20module.), I ran into problems with forward declarations.
I think I finally may have found a pattern to synthetisize a lightweight forward module per package, which can be imported instead of importing the class definition(s).
For example, in our code, we have a package `Core`.
I now have a header file `Core/Forward.h`, which just contains forward declarations of the classes in Core:
#pragma once
namespace Core
{
class CopyRegistry;
class ElementSet;
class Env;
class ExtendSelectionParam;
class IClub;
class IDiagram;
class IDirtyMarker;
class IDirtyStateObserver;
class IDocumentChangeObserver;
class IElement;
class IElementPtr;
class IFilter;
class IGrid;
class IPastePostProcessor;
class IPosOwner;
class ISelectionObserver;
class IUndoRedoCountObserver;
class IObjectRegistry;
class IUndoerCollector;
class IUndoHandler;
class IView;
class IViewElement;
class ObjectID;
class ObjectRegistry;
class PosUndoer;
class SelectionHider;
class SelectionObserverDock;
class SelectionTracker;
class SelectionVisibilityServerImp;
class Transaction;
class TransactionImp;
class Undoer;
class UndoerParam;
class UndoerRef;
class VIPointable;
class VISelectable;
class Weight;
}
I then have created a module `Core.Forward` (in file `Core/Forward.ixx`):
export module Core.Forward;
export import <Core/Forward.h>;
Which uses a [header unit](https://en.cppreference.com/w/cpp/language/modules#:~:text=A%20header%20unit%20is%20a%20separate%20translation%20unit%20synthesized%20from%20a%20header.%20Importing%20a%20header%20unit%20will%20make%20accessible%20all%20its%20definitions%20and%20declarations.).
The resulting interface module can be imported wherever just a forward declaration of a class is enough, instead of the full definition. Which means for example doing
import Core.Forward;
instead of
import Core.IElement;
when class `Core::IElement` is only used by reference in some interface.
I believe this pattern is conformant to the C++ 20 language spec.
### Previous related posts
* [The language spec of C++ 20 modules should be amended to support forward declarations](https://www.reddit.com/r/cpp/comments/1jch40x/the_language_spec_of_c_20_modules_should_be/) in r/cpp
* [C++ modules and forward declarations in partitions](https://www.reddit.com/r/cpp_questions/comments/1jb93al/c_modules_and_forward_declarations_in_partitions/) in r/cpp_questions
* [C++ modules and forward declarations](https://www.reddit.com/r/cpp/comments/1j7ue8o/c_modules_and_forward_declarations/) in r/cpp
https://redd.it/1jd7c5r
@r_cpp
I have ported the C++ sources of our [Windows application](https://www.cadifra.com/) from header files to using C++ 20 modules.
Our codebase is heavily using forward declarations for classes wherever possible.
The code is devided into ~40 packages. Every package uses a namespace and all the files of a package are part of a "Project" in Visual Studio.
Due to the strong [name attaching rules of C++20 modules](https://en.cppreference.com/w/cpp/language/modules#:~:text=In%20general%2C%20if,the%20same%20module.), I ran into problems with forward declarations.
I think I finally may have found a pattern to synthetisize a lightweight forward module per package, which can be imported instead of importing the class definition(s).
For example, in our code, we have a package `Core`.
I now have a header file `Core/Forward.h`, which just contains forward declarations of the classes in Core:
#pragma once
namespace Core
{
class CopyRegistry;
class ElementSet;
class Env;
class ExtendSelectionParam;
class IClub;
class IDiagram;
class IDirtyMarker;
class IDirtyStateObserver;
class IDocumentChangeObserver;
class IElement;
class IElementPtr;
class IFilter;
class IGrid;
class IPastePostProcessor;
class IPosOwner;
class ISelectionObserver;
class IUndoRedoCountObserver;
class IObjectRegistry;
class IUndoerCollector;
class IUndoHandler;
class IView;
class IViewElement;
class ObjectID;
class ObjectRegistry;
class PosUndoer;
class SelectionHider;
class SelectionObserverDock;
class SelectionTracker;
class SelectionVisibilityServerImp;
class Transaction;
class TransactionImp;
class Undoer;
class UndoerParam;
class UndoerRef;
class VIPointable;
class VISelectable;
class Weight;
}
I then have created a module `Core.Forward` (in file `Core/Forward.ixx`):
export module Core.Forward;
export import <Core/Forward.h>;
Which uses a [header unit](https://en.cppreference.com/w/cpp/language/modules#:~:text=A%20header%20unit%20is%20a%20separate%20translation%20unit%20synthesized%20from%20a%20header.%20Importing%20a%20header%20unit%20will%20make%20accessible%20all%20its%20definitions%20and%20declarations.).
The resulting interface module can be imported wherever just a forward declaration of a class is enough, instead of the full definition. Which means for example doing
import Core.Forward;
instead of
import Core.IElement;
when class `Core::IElement` is only used by reference in some interface.
I believe this pattern is conformant to the C++ 20 language spec.
### Previous related posts
* [The language spec of C++ 20 modules should be amended to support forward declarations](https://www.reddit.com/r/cpp/comments/1jch40x/the_language_spec_of_c_20_modules_should_be/) in r/cpp
* [C++ modules and forward declarations in partitions](https://www.reddit.com/r/cpp_questions/comments/1jb93al/c_modules_and_forward_declarations_in_partitions/) in r/cpp_questions
* [C++ modules and forward declarations](https://www.reddit.com/r/cpp/comments/1j7ue8o/c_modules_and_forward_declarations/) in r/cpp
https://redd.it/1jd7c5r
@r_cpp
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
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
#pragma omp for reduction(max:maxres) schedule(static)
for (i = 1; i < NX-1; ++i){
for (j = 1; j < NY-1; ++j){
residual[i][j] = 0.25 * (
phi_new[i + 1][j] + phi_new[i - 1][j] +
phi_new[i][j + 1] + phi_new[i][j - 1]) - phi_new[i][j];
maxres = std::max(maxres, std::abs(residual[i][j]));
}
}
}
if (iter % 100 == 0)
std::cout << "Iter: " << iter << " maxres: " << maxres << "\n";
if (maxres < TOL)
break;
}
double end_time = omp_get_wtime();
std::cout << "Time taken (seconds): " << end_time - start_time << "\n";
return 0;
}
https://redd.it/1kx89hx
@r_cpp
for (i = 1; i < NX-1; ++i){
for (j = 1; j < NY-1; ++j){
residual[i][j] = 0.25 * (
phi_new[i + 1][j] + phi_new[i - 1][j] +
phi_new[i][j + 1] + phi_new[i][j - 1]) - phi_new[i][j];
maxres = std::max(maxres, std::abs(residual[i][j]));
}
}
}
if (iter % 100 == 0)
std::cout << "Iter: " << iter << " maxres: " << maxres << "\n";
if (maxres < TOL)
break;
}
double end_time = omp_get_wtime();
std::cout << "Time taken (seconds): " << end_time - start_time << "\n";
return 0;
}
https://redd.it/1kx89hx
@r_cpp
Reddit
From the cpp community on Reddit
Explore this post and more from the cpp community
Parallel bubble sort with OpenMP — any chance it outperforms sequential version?
Hey everyone,
I’ve been experimenting with OpenMP and tried parallelizing bubble sort — I know it's a bad algorithm overall, but it's a good toy example to test parallelism.
When I try it on integers, the parallel version ends up slower than the single-threaded one, which makes sense: bubble sort is inherently sequential due to the element-by-element comparisons and swaps. The overhead of synchronizing threads and managing shared memory probably kills performance.
But here's where it gets interesting:
When I switch to using floating-point numbers instead of integers, I notice that the performance gap shrinks. In some cases, it's even slightly faster than the sequential version. I have a theory — modern CPUs are optimized for float operations in SIMD/FPU pipelines, so the cost per operation is lower than with integer compare-and-swap logic.
My questions:
Is there any realistic scenario where bubble sort (or odd-even transposition sort) can actually run faster in parallel than sequentially?
Is my observation about float vs int performance plausible, or am I misinterpreting something?
Are there hardware-specific quirks (e.g., FPU vs ALU pipelines, SIMD instructions, cache behavior) that could explain this?
Again, I’m not trying to use bubble sort in production — just using it to understand low-level parallel behavior and OpenMP tradeoffs. Any thoughts or benchmarks would be appreciated!
Update: here's the code I currently use for testing. It’s an odd-even transposition variant, parallelized with OpenMP.
void parallelBubbleSort(vector<int> &arr)
{
size_t n = arr.size();
bool swapped = true;
for (size_t k = 0; k < n - 1 && swapped; ++k)
{
swapped = false;
#pragma omp parallel for shared(arr, swapped)
for (size_t i = 0; i < n - 1; i += 2)
{
if (arr[i] > arr[i + 1])
{
swap(arr[i], arr[i + 1]);
#pragma omp atomic write
swapped = true;
}
}
#pragma omp parallel for shared(arr, swapped)
for (size_t i = 1; i < n - 1; i += 2)
{
if (arr[i] > arr[i + 1])
{
swap(arr[i], arr[i + 1]);
#pragma omp atomic write
swapped = true;
}
}
}
}
I ran this on my university’s cluster with:
Intel Xeon E5-2670 v3 (2 sockets × 12 cores × 2 threads = 48 threads)
L3 cache: 30 MB
125 GiB RAM
AlmaLinux 8.7
The parallel version (with static scheduling and large arrays) still tends to be slower than the sequential one.
I'm wondering how much of this is due to:
cache contention / false sharing
small workload per thread
overhead of synchronization
https://redd.it/1lbx8lp
@r_cpp
Hey everyone,
I’ve been experimenting with OpenMP and tried parallelizing bubble sort — I know it's a bad algorithm overall, but it's a good toy example to test parallelism.
When I try it on integers, the parallel version ends up slower than the single-threaded one, which makes sense: bubble sort is inherently sequential due to the element-by-element comparisons and swaps. The overhead of synchronizing threads and managing shared memory probably kills performance.
But here's where it gets interesting:
When I switch to using floating-point numbers instead of integers, I notice that the performance gap shrinks. In some cases, it's even slightly faster than the sequential version. I have a theory — modern CPUs are optimized for float operations in SIMD/FPU pipelines, so the cost per operation is lower than with integer compare-and-swap logic.
My questions:
Is there any realistic scenario where bubble sort (or odd-even transposition sort) can actually run faster in parallel than sequentially?
Is my observation about float vs int performance plausible, or am I misinterpreting something?
Are there hardware-specific quirks (e.g., FPU vs ALU pipelines, SIMD instructions, cache behavior) that could explain this?
Again, I’m not trying to use bubble sort in production — just using it to understand low-level parallel behavior and OpenMP tradeoffs. Any thoughts or benchmarks would be appreciated!
Update: here's the code I currently use for testing. It’s an odd-even transposition variant, parallelized with OpenMP.
void parallelBubbleSort(vector<int> &arr)
{
size_t n = arr.size();
bool swapped = true;
for (size_t k = 0; k < n - 1 && swapped; ++k)
{
swapped = false;
#pragma omp parallel for shared(arr, swapped)
for (size_t i = 0; i < n - 1; i += 2)
{
if (arr[i] > arr[i + 1])
{
swap(arr[i], arr[i + 1]);
#pragma omp atomic write
swapped = true;
}
}
#pragma omp parallel for shared(arr, swapped)
for (size_t i = 1; i < n - 1; i += 2)
{
if (arr[i] > arr[i + 1])
{
swap(arr[i], arr[i + 1]);
#pragma omp atomic write
swapped = true;
}
}
}
}
I ran this on my university’s cluster with:
Intel Xeon E5-2670 v3 (2 sockets × 12 cores × 2 threads = 48 threads)
L3 cache: 30 MB
125 GiB RAM
AlmaLinux 8.7
The parallel version (with static scheduling and large arrays) still tends to be slower than the sequential one.
I'm wondering how much of this is due to:
cache contention / false sharing
small workload per thread
overhead of synchronization
https://redd.it/1lbx8lp
@r_cpp
Reddit
From the cpp community on Reddit
Explore this post and more from the cpp community
(advanced) linker madness on visual studio 2022.
Hi,
Im really stuck here and cannot for the life of me figure out what's going on. Im thinking an issue with visual studio linker, but not sure.
I have generated code (its protoc generated) and there are LOT and LOTS of generated classes. So many that we hit the COFF/PE 64k limit on exported symbols at link time. This is a critical issue for us.
Right now the nature of our app , doesnt currently allow us to split/separate out the .protos. Its just the way it is (for the moment).
My solution to reducing the exported symbol count;
Instead of having the protoc generated classes export every thing like this;
class PROTOBUF_EXPORTS Object : public google::protobuf::Message
{
// all the methods / constructor/destructor etc.
// lots and lots of unused methods etc exported.
}
I have a python script that correctly alters the generated code to ONLY export the symbols we need. In addition it adds one (the key) virtual void foo(); function.
so the script modified code looks like;
class Object : public google::protobuf::Message
{
PROTOBUF_EXPORTS Object();
PROTOBUF_EXPORTS virtual \~Object();
PROTOBUF_EXPORTS virtual void Swap(Object* other);
PROTOBUF_EXPORTS virtual void foo();
// a few other key methods that our clients will call.....
};
the added "virtual void foo()" is added to the .cc file correctly.
i.e. the intention is to export (via __declspec(dllexport) ONLY the functions our client code needs, thereby significantly reducing the number of symbols exported in the .dll)
Despite the fact that the "virtual void foo()" function is in there (key function for vtable emission, as I understand it) , I was getting unresolved externals for all these Objects;
"unresolved external Object::`vftable"
"unresolved external Bar::`vftable"
"unresolved external Foo::`vftable"
"unresolved external Blah::`vftable"
(lots of others too, for all our Message objects. The only way I could get the library in question to link correctly (tried #pragma link /export and #pragma link /include but to no avail) , was to use a .def file and for the vftable to be exported. this works a treat for the dll being built in question.
With this approach
dumpbin /exports on the dll works and I can see all the mangled Object::`vftable symbols. Similarly in the corresponding .lib file, "dumpbin /symbols" on the .lib file shows everything exactly as I want it (all the vftable symbols are in there.)
BUT ... and this is the big blocker I CANNOT resolve;
When I link OUR dll (the client... that imports those same symbols via __declspec(dllimport)) against the dll above, the vftable unresolved externals reappear. They shouldnt, they are defined in the dll and .lib and dumpbin /exports and dumpbin /symbols on the .dll and .lib respectively proves it. The names are IDENTICAL (trust me I've verified).
Can anybody help me?
https://redd.it/1mepvlg
@r_cpp
Hi,
Im really stuck here and cannot for the life of me figure out what's going on. Im thinking an issue with visual studio linker, but not sure.
I have generated code (its protoc generated) and there are LOT and LOTS of generated classes. So many that we hit the COFF/PE 64k limit on exported symbols at link time. This is a critical issue for us.
Right now the nature of our app , doesnt currently allow us to split/separate out the .protos. Its just the way it is (for the moment).
My solution to reducing the exported symbol count;
Instead of having the protoc generated classes export every thing like this;
class PROTOBUF_EXPORTS Object : public google::protobuf::Message
{
// all the methods / constructor/destructor etc.
// lots and lots of unused methods etc exported.
}
I have a python script that correctly alters the generated code to ONLY export the symbols we need. In addition it adds one (the key) virtual void foo(); function.
so the script modified code looks like;
class Object : public google::protobuf::Message
{
PROTOBUF_EXPORTS Object();
PROTOBUF_EXPORTS virtual \~Object();
PROTOBUF_EXPORTS virtual void Swap(Object* other);
PROTOBUF_EXPORTS virtual void foo();
// a few other key methods that our clients will call.....
};
the added "virtual void foo()" is added to the .cc file correctly.
i.e. the intention is to export (via __declspec(dllexport) ONLY the functions our client code needs, thereby significantly reducing the number of symbols exported in the .dll)
Despite the fact that the "virtual void foo()" function is in there (key function for vtable emission, as I understand it) , I was getting unresolved externals for all these Objects;
"unresolved external Object::`vftable"
"unresolved external Bar::`vftable"
"unresolved external Foo::`vftable"
"unresolved external Blah::`vftable"
(lots of others too, for all our Message objects. The only way I could get the library in question to link correctly (tried #pragma link /export and #pragma link /include but to no avail) , was to use a .def file and for the vftable to be exported. this works a treat for the dll being built in question.
With this approach
dumpbin /exports on the dll works and I can see all the mangled Object::`vftable symbols. Similarly in the corresponding .lib file, "dumpbin /symbols" on the .lib file shows everything exactly as I want it (all the vftable symbols are in there.)
BUT ... and this is the big blocker I CANNOT resolve;
When I link OUR dll (the client... that imports those same symbols via __declspec(dllimport)) against the dll above, the vftable unresolved externals reappear. They shouldnt, they are defined in the dll and .lib and dumpbin /exports and dumpbin /symbols on the .dll and .lib respectively proves it. The names are IDENTICAL (trust me I've verified).
Can anybody help me?
https://redd.it/1mepvlg
@r_cpp
Reddit
From the cpp community on Reddit
Explore this post and more from the cpp community