Skip to content

Build-C-as-C++ Patches#849

Open
AE1020 wants to merge 3 commits into
RoaringBitmap:masterfrom
AE1020:simple-cplusplus-patches
Open

Build-C-as-C++ Patches#849
AE1020 wants to merge 3 commits into
RoaringBitmap:masterfrom
AE1020:simple-cplusplus-patches

Conversation

@AE1020

@AE1020 AE1020 commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

As per C++ core guidelines CPL.2, it's best for C code to be buildable with a C++ compiler. (my codebase using CRoaring has to build as both C99+ and C++11+). Because of this I had contributed some of the necessary changes to CRoaring to achieve that some years ago.

At that time, I also slipped in some "experimental" ideas involving how container_t* could be a void* in C, but in C++ it could use the "empty base class optimization" with the container subclasses inheriting from it. This meant it would be type checked more strongly if built as C++...so that you got the benefit of typed inheritance...only allowing containers to be passed to container_t* vs arbitrary pointers.

It was the start of a good idea, but only the start (and the way I did it then was often more clutter than it provided benefit, as well as an ABI break with C-built code in some compilers in some circumstances). Those ideas have evolved into a vastly richer framework now... which may be applied to many problems. Including solving your memory allocation failures/propagation in a "Rust-like" way, by using the type system to annotate the return values of routines that can fail, and forcing compile-time errors when triage is not performed:

https://needful.metaeducation.com/

This new model removes the wacky C++ from CRoaring's codebase entirely; the "enhancements" are in a repository that only those who wish to build with instrumentation "install". It becomes a tool that you sideload in certain developer/CI builds--not part of CRoaring itself. (Your focus on "amalgamation" demonstrates you are interested in pragmatic packaging, and Needful is also very pragmatic: removing the clutter, while delivering the benefit.)

Which is good: e.g. in my fork I've eliminated of all the below kind of junk, while delivering the actual value that a "C++ enhanced build" was theoretically supposed to provide:

#ifdef __cplusplus
#define CAST(type, value) static_cast<type>(value)
#define movable_CAST(type, value) movable_CAST_HELPER<type>(value)
template <typename PPDerived, typename Base>
PPDerived movable_CAST_HELPER(Base **ptr_to_ptr) {
typedef typename std::remove_pointer<PPDerived>::type PDerived;
typedef typename std::remove_pointer<PDerived>::type Derived;
static_assert(std::is_base_of<Base, Derived>::value,
"use movable_CAST() for container_t** => xxx_container_t**");
return reinterpret_cast<Derived **>(ptr_to_ptr);
}
#else
#define CAST(type, value) ((type)value)
#define movable_CAST(type, value) ((type)value)
#endif

#define CAST_array(c) CAST(array_container_t *, c) // safer downcast
#define const_CAST_array(c) CAST(const array_container_t *, c)
#define movable_CAST_array(c) movable_CAST(array_container_t **, c)

(etc.) This is all gone, replaced by a (via a single downcast operator), that's just #define downcast (void*) in the baseline C distribution (and minor magic in non-enhanced C++ builds)... but metaprogramming sorcery once you sideload the C++ enhanced files. It detects the target type implicitly without you having to say what it is and validates the inheritance relationship, it won't downcast const pointers to non-const, it won't cast double-pointers to single ones, it can compile-time restrict the allowed to and from casts, or runtime validate the bit patterns based on what you're casting to what, and so on and so forth...


But to get the ball rolling to show you what I mean, the atrophy in C++ builds has to be fixed first. Here are some (I hope) uncontroversial patches to start with.

AE1020 added 2 commits July 16, 2026 20:59
There is already a uint32_max defined in the file globally as a
shorthand for the constant from std::numeric_limits.
It's defined in the same file.

This is a similar solution to PR 326

RoaringBitmap#326 (comment)
@AE1020
AE1020 force-pushed the simple-cplusplus-patches branch from dc78340 to 2575e12 Compare July 17, 2026 00:59
The bitset_t was once an internal implementation detail, but was made
a part of the api.  The roaring::internal namespace was still being
used on bitset_t.

This moves it to the API namespace.  Also, the `misc` namespace where
the configreport put its routines was not being included in some
places.  This fixes that.

Finally, the various containers were being exposed as api vs. internal.
While things like the iterators are api, things like run_container_t
should be internal.
@AE1020
AE1020 force-pushed the simple-cplusplus-patches branch from 2575e12 to f8ef82b Compare July 17, 2026 11:28
Comment thread tests/c_example1.c
#include "test.h"

#ifdef __cplusplus // stronger type checking errors if C built in C++ mode
using namespace roaring::api;

@AE1020 AE1020 Jul 17, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Upon review I notice this line is actually superfluous: including roaring.h (as opposed to roaring.hh) when building as __cplusplus) automatically includes the roaring::api namespace.

https://github.com/RoaringBitmap/CRoaring/blob/master/include/roaring/roaring.h#L1367-L1382

Perhaps that points to a potential separation of configreport.h vs. configreport.hh that does a similar trick; you don't need a using namespace roaring::misc; if you use the .h version?

@AE1020 AE1020 changed the title Simple cplusplus patches Build-C-as-C++ Patches Jul 17, 2026
Comment thread src/bitset.c
extern "C" {
namespace roaring {
namespace internal {
namespace api { // bitset_t was once internal, but made public in the API

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this comment belongs in the code. That's information for the Git commit message.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants