Skip to content

Commit 4d69e7d

Browse files
gennaroprotalouistatta
authored andcommitted
Add Gennaro's 2025 Q3 update
1 parent fb0eb07 commit 4d69e7d

File tree

1 file changed

+146
-0
lines changed

1 file changed

+146
-0
lines changed
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
---
2+
layout: post
3+
nav-class: dark
4+
categories: gennaro
5+
title: "DynamicBitset Reimagined: A Quarter of Flexibility, Cleanup, and Modern C++"
6+
author-id: gennaro
7+
author-name: Gennaro Prota
8+
---
9+
10+
Over the past three months, I've been immersed in a deep and wide-ranging
11+
overhaul of the Boost.DynamicBitset library. What started as a few targeted
12+
improvements quickly evolved into a full-scale modernization effort—touching
13+
everything from the underlying container to iterator concepts, from test
14+
coverage to documentation style. More than 170 commits later, the library is
15+
leaner, more flexible, and better aligned with modern C++ practices.
16+
17+
## Making the core more flexible
18+
19+
The most transformative change this quarter was allowing users to choose the
20+
underlying container type for `dynamic_bitset`. Until now, the implementation
21+
assumed `std::vector`, which limited optimization opportunities and imposed
22+
certain behaviors. By lifting that restriction, developers can now use
23+
alternatives like `boost::container::small_vector`, enabling small buffer
24+
optimization and more control over memory layout.
25+
26+
This change had ripple effects throughout the codebase. I had to revisit
27+
assumptions about contiguous storage, update operators like `<<=`, `>>=`, and
28+
ensure that reference stability and iterator behavior were correctly handled.
29+
30+
## Introducing C++20 iterators
31+
32+
One of the more exciting additions this quarter was support for C++20-style
33+
iterators. These new iterators conform to the standard iterator concepts, making
34+
`dynamic_bitset` more interoperable with modern algorithms and range-based
35+
utilities.
36+
37+
I added assertions to ensure that both the underlying container and
38+
`dynamic_bitset` itself meet the requirements for bidirectional iteration. These
39+
checks are enabled only when compiling with C++20 or later, and they help catch
40+
subtle mismatches early—especially when users plug in custom containers.
41+
42+
## Saying goodbye to legacy workarounds
43+
44+
With modern compilers and standard libraries, many old workarounds are no longer
45+
needed. I removed the `max_size_workaround()` after confirming that major
46+
implementations now correctly account for allocators in `max_size()`. I also
47+
dropped support for obsolete compilers like MSVC 6 and CodeWarrior 8.3, and for
48+
pre-standard iostreams, cleaned up outdated macros, and removed compatibility
49+
layers for pre-C++11 environments.
50+
51+
These removals weren't just cosmetic—they simplified the code and made it easier
52+
to reason about. In many places, I replaced legacy constructs with standard
53+
features like `noexcept` and `std::move()`.
54+
55+
## constexpr support
56+
57+
When it is compiled as C++20 or later, almost all functions in DynamicBitset are
58+
now `constexpr`.
59+
60+
## Dropping obsolete dependencies
61+
62+
As part of the cleanup effort, I also removed several outdated dependencies that
63+
were no longer justified. These included Boost.Integer (previously used by
64+
`lowest_bit()`), `core/allocator_access.hpp`, and various compatibility headers
65+
tied to pre-C++11 environments. This not only reduces compile-time overhead and
66+
cognitive load, but also makes the library easier to audit and maintain.
67+
68+
69+
## Strengthening the test suite
70+
71+
A part of this quarter's work was expanding and refining the test coverage. I
72+
added new tests for `flip()`, `resize()`, `swap()`, and `operator!=()`. I also
73+
ensured that input iterators are properly supported in `append()`, and verified
74+
that `std::hash` behaves correctly even when two bitsets share the same
75+
underlying container but differ in size.
76+
77+
Along the way, I cleaned up misleading comments, shortened overly complex
78+
conditions, and removed legacy test code that no longer reflected the current
79+
behavior of the library. The result is a test suite that's more robust, more
80+
meaningful, and easier to maintain.
81+
82+
## Documentation that speaks clearly
83+
84+
I've always believed that documentation should be treated as part of the design,
85+
not an afterthought. This quarter, I ported the existing documentation to MrDocs
86+
and Antora, while fixing and improving a few bits in the process. This uncovered
87+
a few MrDocs bugs, some of which remain—but I'm hopeful.
88+
89+
I also spent time harmonizing the style and structure of the library's comments
90+
and docstrings.
91+
92+
I chose to document iterator categories rather than exposing concrete types,
93+
which keeps the interface clean and focused on behavior rather than
94+
implementation details.
95+
96+
## New member functions and smarter implementations
97+
98+
This quarter also introduced several new member functions that expand the
99+
expressiveness and utility of `dynamic_bitset`:
100+
101+
- `push_front()` and `pop_front()` allow bit-level manipulation at the front of
102+
the bitset, complementing the existing back-oriented operations.
103+
- `find_first_off()` and `find_next_off()` provide symmetric functionality to
104+
their `find_first()` counterparts, making it easier to locate unset bits.
105+
- A constructor from `basic_string_view` was added for C++17 and later,
106+
improving interoperability with modern string APIs.
107+
108+
Alongside these additions, I revisited the implementation of several existing
109+
members to improve performance and clarity:
110+
111+
- `push_back()` and `pop_back()` were streamlined for better efficiency.
112+
- `all()` and `lowest_bit()` were simplified and optimized, with the latter also
113+
shedding its dependency on Boost.Integer.
114+
- `append()` was fixed to properly support input iterators and avoid redundant
115+
checks.
116+
117+
## Minor but impactful cleanups
118+
119+
A large number of small edits improved correctness, readability, and
120+
maintainability:
121+
122+
- Fixed the stream inserter to set `badbit` if an exception is thrown during
123+
output.
124+
- Changed the stream extractor to rethrow any exceptions coming from the
125+
underlying container.
126+
- Reordered and cleaned up all #include sections to use the "" form for Boost
127+
includes where appropriate and to keep include groups sorted.
128+
- Removed an example timing benchmark that was misleading and a number of
129+
unneeded comments and minor typos across code and docs.
130+
131+
These edits reduce noise and make code reviews and maintenance more pleasant.
132+
133+
## Reflections
134+
135+
Looking back, this quarter reminded me of the value of revisiting assumptions.
136+
Many of the workarounds and constraints that once made sense are now obsolete.
137+
By embracing modern C++ features and simplifying where possible, we can make
138+
libraries like `dynamic_bitset` more powerful and more approachable.
139+
140+
It also reinforced the importance of clarity—both in code and in documentation.
141+
Whether it's a test case, a comment, or a public API, precision and consistency
142+
go a long way.
143+
144+
The work continues, but the foundation is stronger than ever. If you're using
145+
`dynamic_bitset` or thinking about integrating it into your project, I'd love to
146+
hear your feedback.

0 commit comments

Comments
 (0)