Skip to content

feat: migrate Wildcard to modern smart pointers #105

Open
luanluciano93 wants to merge 9 commits intoatlas-kit:devfrom
luanluciano93:wildcard-to-smart-pointers
Open

feat: migrate Wildcard to modern smart pointers #105
luanluciano93 wants to merge 9 commits intoatlas-kit:devfrom
luanluciano93:wildcard-to-smart-pointers

Conversation

@luanluciano93
Copy link
Copy Markdown
Collaborator

@luanluciano93 luanluciano93 commented Dec 22, 2025

Pull Request Prelude

Changes Proposed

Issues addressed: #40

How to test:

Summary by CodeRabbit

  • Refactor
    • Safer node access: replaced raw pointer returns with optional reference semantics to eliminate null-pointer usage and improve explicit absence handling.
    • Child creation now yields references instead of raw pointers for clearer ownership.
    • Minor constructor/style cleanup and other small internal cleanups to reduce clutter.

✏️ Tip: You can customize this high-level summary in your review settings.

@ranisalt ranisalt moved this to In progress in Tech debt Dec 23, 2025
@ranisalt ranisalt force-pushed the wildcard-to-smart-pointers branch from ec356c0 to 1dc25e3 Compare January 6, 2026 17:36
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 6, 2026

📝 Walkthrough

Walkthrough

Changed WildcardTreeNode public API: getChild(char) now returns std::optional<std::reference_wrapper<...>> (const and non-const overloads) instead of raw pointers; addChild(char, bool) now returns WildcardTreeNode&. Call sites and includes adjusted accordingly.

Changes

Cohort / File(s) Summary
Header: API
src/wildcardtree.h
getChild(char) signatures changed from WildcardTreeNode* / const WildcardTreeNode* to [[nodiscard]] std::optional<std::reference_wrapper<WildcardTreeNode>> and [[nodiscard]] std::optional<std::reference_wrapper<const WildcardTreeNode>>. addChild(char,bool) now returns WildcardTreeNode&. Constructor initializer style updated.
Implementation: logic & call sites
src/wildcardtree.cpp
Implementations updated to produce and consume std::optional<std::reference_wrapper<...>> for lookups and to return references from addChild. Call sites (insert, remove, findOne, traversal) updated to handle optionals and reference wrappers (dereference via .value() / .get() or structured bindings), and #include <tuple> removal.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I hopped through nodes, now optional with grace,

Ref-wrapped friends take the pointer's place.
addChild returns a steady paw,
getChild answers with maybe—ah!—or naw.
A tiny rabbit cheers the new API's pace.

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title check ⚠️ Warning The title claims migration to 'smart pointers', but the actual changes replace raw pointers with std::optional<std::reference_wrapper<>>, which is not a smart pointer pattern. Revise title to accurately reflect the changes, such as: 'refactor: replace raw pointers with optional reference wrappers in WildcardTree' or 'refactor: use std::optional for safer child node access'.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/wildcardtree.h (1)

13-17: Consider declaring move assignment operator for consistency.

The class explicitly defaults the move constructor but doesn't declare the move assignment operator. While the compiler-generated move assignment will work correctly with unique_ptr members, explicitly declaring it would be more consistent with the Rule of Five pattern.

🔎 Suggested addition
 	WildcardTreeNode(WildcardTreeNode&& other) = default;
+	WildcardTreeNode& operator=(WildcardTreeNode&&) = default;

 	// non-copyable
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d32428c and 1dc25e3.

📒 Files selected for processing (2)
  • src/wildcardtree.cpp
  • src/wildcardtree.h
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: ubuntu
  • GitHub Check: test
  • GitHub Check: windows
  • GitHub Check: docker-image
🔇 Additional comments (7)
src/wildcardtree.h (2)

21-21: Good API design: returning reference instead of pointer.

Returning a reference guarantees a valid node is always returned, eliminating null checks at call sites. This is a cleaner contract for addChild since it always succeeds.


29-29: Proper use of std::unique_ptr for child node ownership.

The migration to std::unique_ptr correctly expresses exclusive ownership semantics and ensures automatic cleanup of child nodes.

src/wildcardtree.cpp (5)

10-17: Correct accessor pattern for smart pointer storage.

Both getChild overloads correctly use .get() to return a non-owning raw pointer, which is the appropriate pattern when exposing internal unique_ptr-managed objects without transferring ownership.

Also applies to: 19-26


28-42: Well-implemented ownership transfer in addChild.

The implementation correctly:

  1. Checks for existing child and returns early (line 35)
  2. Captures the reference before moving the unique_ptr (lines 37-39)
  3. Returns the reference to the now-owned object (line 40)

This pattern avoids undefined behavior that would occur if you tried to dereference after std::move.


44-54: Correctly adapted to new addChild return type.

Taking the address of the returned reference (&cur->addChild(...)) is the correct way to continue traversal when the calling code uses pointers.


56-88: remove() correctly works with the new storage model.

The removal logic properly:

  • Traverses using getChild() which returns raw pointers
  • Erases from the map, which automatically destroys the unique_ptr and its managed node

110-113: Correct traversal update for smart pointer storage.

Using it->second.get() correctly obtains the raw pointer for traversal without affecting ownership.

@ranisalt
Copy link
Copy Markdown

ranisalt commented Jan 6, 2026

I don't think this one helps, it's creating a second indirection to access the nodes and it was already not using pointers. It would maybe be a better approach for these methods to return std::optional<T&> or std::expected

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI Agents
In @src/wildcardtree.cpp:
- Around line 10-26: The current WildcardTreeNode::getChild overloads return
std::optional<std::reference_wrapper<...>> which forces verbose usage; change
both overloads to return raw pointers (WildcardTreeNode* for the non-const and
const WildcardTreeNode* for the const overload), have them look up `children`
and return the found node pointer or nullptr when not found, and update call
sites to check for nullptr (or add a simple hasChild(char) that uses
children.find to preserve existing call patterns). Ensure both
WildcardTreeNode::getChild implementations and any call sites using ->get() or
.value().get() are updated accordingly.
- Line 30: There is a stray empty statement (a lone ';') in src/wildcardtree.cpp
left from refactoring; remove that semicolon so there is no standalone empty
statement in the file (ensure surrounding code compiles cleanly after removal).
🧹 Nitpick comments (1)
src/wildcardtree.cpp (1)

35-35: Consider more explicit dereferencing.

While return *node; works due to implicit conversion from std::reference_wrapper<T> to T&, it's not immediately obvious. Consider using return node->get(); for clarity.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1dc25e3 and c34cd81.

📒 Files selected for processing (2)
  • src/wildcardtree.cpp
  • src/wildcardtree.h
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/wildcardtree.h
🧰 Additional context used
🧬 Code graph analysis (1)
src/wildcardtree.cpp (1)
src/wildcardtree.h (1)
  • WildcardTreeNode (9-31)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: windows
  • GitHub Check: ubuntu
  • GitHub Check: docker-image
  • GitHub Check: test
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (3)
src/wildcardtree.cpp (3)

42-52: Implementation is correct.

The use of &cur->addChild(...) to convert the returned reference to a pointer is valid. However, this pattern highlights the mixed pointer/reference style introduced by the new API.


54-86: Implementation is correct.

The usage of node->get() to access the wrapped reference is correct. While verbose, it's consistent with the new API design.


88-113: Implementation is correct.

The method correctly uses the new API, including proper handling of std::optional and structured binding for map iteration.

Comment thread src/wildcardtree.cpp
Comment on lines +10 to 26
std::optional<std::reference_wrapper<WildcardTreeNode>> WildcardTreeNode::getChild(char ch)
{
auto it = children.find(ch);
if (it == children.end()) {
return nullptr;
return std::nullopt;
}
return &it->second;
return it->second;
}

const WildcardTreeNode* WildcardTreeNode::getChild(char ch) const
std::optional<std::reference_wrapper<const WildcardTreeNode>> WildcardTreeNode::getChild(char ch) const
{
auto it = children.find(ch);
if (it == children.end()) {
return nullptr;
return std::nullopt;
}
return &it->second;
return it->second;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Consider the added complexity of std::optional<std::reference_wrapper>.

While the implementation is correct, the reviewer ranisalt raised a valid concern: this API introduces additional indirection and complexity compared to returning a raw pointer. The pattern std::optional<std::reference_wrapper<T>> requires verbose access patterns (->get() or .value().get()) at every call site, as seen throughout the code.

Consider alternatives that maintain safety while reducing complexity:

  • Return WildcardTreeNode* (nullptr on not found) - simpler and direct
  • Restructure the API to avoid optional returns (e.g., separate hasChild + getChild methods, or use iterators)
  • Wait for C++23's std::optional<T&> support (if applicable)

Based on the PR comment from ranisalt.

🤖 Prompt for AI Agents
In @src/wildcardtree.cpp around lines 10 - 26, The current
WildcardTreeNode::getChild overloads return
std::optional<std::reference_wrapper<...>> which forces verbose usage; change
both overloads to return raw pointers (WildcardTreeNode* for the non-const and
const WildcardTreeNode* for the const overload), have them look up `children`
and return the found node pointer or nullptr when not found, and update call
sites to check for nullptr (or add a simple hasChild(char) that uses
children.find to preserve existing call patterns). Ensure both
WildcardTreeNode::getChild implementations and any call sites using ->get() or
.value().get() are updated accordingly.

Comment thread src/wildcardtree.cpp Outdated
if (child) {
if (breakpoint && !child->breakpoint) {
child->breakpoint = true;
;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove the empty statement.

Line 30 contains an empty statement ; that appears to be leftover from refactoring.

🔎 Proposed fix
 WildcardTreeNode& WildcardTreeNode::addChild(char ch, bool breakpoint)
 {
-	;
 	if (const auto& node = getChild(ch)) {
🤖 Prompt for AI Agents
In @src/wildcardtree.cpp at line 30, There is a stray empty statement (a lone
';') in src/wildcardtree.cpp left from refactoring; remove that semicolon so
there is no standalone empty statement in the file (ensure surrounding code
compiles cleanly after removal).

@codacy-production
Copy link
Copy Markdown

codacy-production Bot commented May 2, 2026

Not up to standards ⛔

🔴 Issues 2 medium

Alerts:
⚠ 2 issues (≤ 0 issues of at least minor severity)

Results:
2 new issues

Category Results
ErrorProne 2 medium

View in Codacy

🟢 Metrics 0 complexity

Metric Results
Complexity 0

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

luanluciano93 and others added 2 commits May 2, 2026 16:45
…ection

- remove() was not advancing cur through the loop, so children were
  looked up on the root and the breakpoint was cleared on the wrong node.
- Reverted std::map<char, std::unique_ptr<T>> to std::map<char, T>; map
  storage is already stable and the extra heap allocation per node was
  unnecessary.
- Added explicit <functional> and <optional> includes; replaced piecewise
  emplace with try_emplace so <tuple> is no longer needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

2 participants