Refactor/cpp lab overhaul - #64
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LEsQ7AcLHafb1tAgosoJFz
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LEsQ7AcLHafb1tAgosoJFz
Adding an example used to mean writing an IExample subclass, repeating the
group name, and remembering to add the file to a source list in CMake - a file
that was missing from the list simply never appeared in the menu. Menu entries
were also unordered, so the numbers changed between runs.
Framework (include/lab, src/lab):
- LAB_EXAMPLE("Name", "description" [, lab::kInteractive]) { ... } registers a
file-local function before main() runs; the menu group is derived from the
file's location, so ids like core/smart_pointer/Weak always match the tree.
- lab::Registry keeps examples sorted and rejects duplicate ids and invalid
names instead of failing silently.
- Folder-style menu with search, plus a command line: --list, --run,
--run-all, --list-ids, --plain, --mode, --version, --help.
- Logger gained LOG_FUNC/LOG_SECTION, colors only on a terminal, and a working
Release build (the old release path could not compile LOG(string_view)).
Build:
- Example modules are globbed with CONFIGURE_DEPENDS, so no CMake edit is
needed for a new example; OBJECT libraries keep the static registrations.
- Options: CPPLAB_BUILD_TESTS/DEMOS/GUI, CPPLAB_ENABLE_SANITIZERS,
CPPLAB_WARNINGS_AS_ERRORS, ENABLE_COVERAGE. gtkmm-4.0 is now optional.
- Warnings, coverage and sanitizer flags moved to a cpplab::options target so
they no longer apply to GoogleTest.
- One ctest smoke test per non-interactive example, discovered at test time.
Examples: all ~100 rewritten with a "what you will learn" header, sections,
fixed bugs (leaks in Command/Memento/Visitor, Builder's build() leaving a null
product, iterator vs nullptr comparison in UnorderedMap, wrong labels in
TemplateMethod, Dollars->Cents conversion, showpos demo, wcout/cout mixing,
a global set_terminate that stayed installed) and modern C++ (unique_ptr
ownership, ranges, concepts, std::format, jthread, variant). Examples no
longer execute undefined behavior or leave files behind, so the whole suite
passes under ASan/UBSan.
Sockets: TCPServer/TCPClient now report errno through std::system_error, close
their sockets exactly once, can stop a blocked accept(), and support port 0;
the new LoopbackEcho example runs a server thread and a client in one process.
Also: PID controller uses a unique_ptr pimpl and validates its parameters,
tests cover the framework, the PID and GoogleTest/GoogleMock usage, and the
GTK apps escape user text before building Pango markup.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LEsQ7AcLHafb1tAgosoJFz
- README: quick start, menu and command line, how to add an example, build options, testing (including sanitizers and valgrind), static analysis, coverage, the standalone programs, VS Code debugging, Docker and troubleshooting. - docs/adding-examples.md: the anatomy of an example, LAB_EXAMPLE, logging, conventions (anonymous namespaces, no undefined behavior, temp files) and how to add a new module. - docs/README.md now indexes every topic; new READMEs for basics, datatype, function, linkage, smart_pointer, string, exception, concurrency and controller, and example tables in the existing ones. - CLAUDE.md describes the framework, the house rules for examples and the traps found while working here (cppcheck needs -I include, .clang-format must stay on c++20 or it mangles digit separators). - scripts/new_example.sh scaffolds an example from a template; run.sh also runs the tests; the coverage scripts use ENABLE_COVERAGE and their own build directory. - CI runs cppcheck with the shared suppression list and adds a second job that builds with sanitizers and runs the whole suite again. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LEsQ7AcLHafb1tAgosoJFz
- ENABLE_COVERAGE now compiles with -fprofile-update=atomic. The RaceCondition example increments a counter from several threads on purpose, which also raced gcov's counters and made lcov abort with "unexpected negative count". - The coverage scripts use their own build-coverage directory, build in parallel, and only open the HTML report when a desktop session is present (and never fail because of it). lcov now reports 90.8% line coverage. - --run-all with a filter that matches nothing says so instead of printing "Ran 0 example(s)". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LEsQ7AcLHafb1tAgosoJFz
clang-tidy found real issues and a lot of noise that comes from the teaching style of the examples. Fixed: - Adapter rounded money with (x + 0.5) instead of std::lround. - Builder used rfind(..., 0) != 0 instead of starts_with, and built its description with temporary strings. - Unique used reset(new T) where make_unique is the point of the example. - Stack had a nested conditional operator; Internal.cpp and ThrowNoexcept used names that do not follow the project's own naming rules. - LAB_EXAMPLE now parenthesizes its macro arguments. - CString's strncat truncation demo silences -Wstringop-truncation locally: it only fires in optimized builds, and truncating is exactly what it shows. Configured: - .clang-tidy disables the checks that contradict the didactic style (copies that show a constructor call, moved-from objects that are inspected, explicit types, recursion, std::bind, ...) and explains each one. The explanation sits above the list, because a YAML folded scalar cannot contain comments - inside it the "comments" silently became part of the check names. - abseil-* checks removed: this project does not use abseil. CI gained a Release job with -Werror; optimized builds report diagnostics that a Debug build never shows (that is how the strncat warning surfaced). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LEsQ7AcLHafb1tAgosoJFz
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LEsQ7AcLHafb1tAgosoJFz
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LEsQ7AcLHafb1tAgosoJFz
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LEsQ7AcLHafb1tAgosoJFz
Eight stages from initialization to sockets and firmware, with the take away for each example, so the lab can be worked through in a sensible order instead of alphabetically. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LEsQ7AcLHafb1tAgosoJFz
Replace rfind(x, 0) == 0 with starts_with, std::string_view::npos for option.npos, rename the command line lambdas and the local error message to lower_case, pass the MVC widget colour by value, reserve in the registry test helper, give FakeTurtle's switch a default case, and rename the Logger's source_location parameter to loc so the declarations fit in 80 columns. tests/dummy keeps scratch code exactly as it is written upstream, so a local .clang-tidy disables every check there instead of reformatting it. Also run clang-format over the tree: nine files had drifted. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LEsQ7AcLHafb1tAgosoJFz
cmake/Docs.cmake adds an optional "docs" target that fills docs/Doxyfile.in into build/Doxyfile and runs Doxygen: the README is the front page, the guides and module READMEs become related pages, and every source file is browsable and cross-linked. The target only exists when doxygen is installed, and it is not part of "all". .github/workflows/docs.yml builds the site on every push and pull request with CPPLAB_DOCS_WARNINGS_AS_ERRORS=ON and deploys it to GitHub Pages from master. docs/doxygen.md explains the local workflow, the one-time Pages setup and how to point the GitHub wiki at the result; scripts/publish_wiki.sh generates that wiki Home page. The Markdown needed small fixes to parse cleanly: Doxygen wants a blank line before a fenced code block, reads a bare <random> in prose as an HTML tag and rejects a fence that hangs off a list item. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LEsQ7AcLHafb1tAgosoJFz
Audit of every module against the feature lists of C++11 to C++23, written up in docs/cpp-standards-coverage.md: 48 topics had no example. Each one now has a file that states what it should teach, prints that outline when it runs, and is registered with the new lab::kDraft flag, so the menu and --list mark it [draft] and the ctest smoke tests still cover it. The gaps were, by module: a whole templates module (function and class templates, specialization, NTTPs, concepts, SFINAE, CRTP, variable templates, two-phase lookup), move semantics and perfect forwarding, inheritance, abstract interfaces, static members, deducing this, attributes, literals, std::byte and <bit>, list/forward_list/map/multimap/unordered_set/flat_map, tuple, any, bitset, random, expected, numeric, ranges, source_location, span, mdspan, the <utility> helpers, atomic, shared_mutex, latches and barriers, coroutines, parallel algorithms, error codes, the ODR, modules, std::print, the Interpreter pattern and the pImpl and type-erasure idioms. scripts/new_example.sh --draft scaffolds the same shape for a new topic. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LEsQ7AcLHafb1tAgosoJFz
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LEsQ7AcLHafb1tAgosoJFz
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LEsQ7AcLHafb1tAgosoJFz
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.