22// This file is part of the CPP-GL project (https://github.com/SpectraL519/cpp-gl).
33// Licensed under the MIT License. See the LICENSE file in the project root for full license information.
44
5+ // / @file gl/algorithm/core.hpp
6+ // / @brief Core data structures and types used to control and track graph algorithm execution.
7+
58#pragma once
69
710#include " gl/attributes/force_inline.hpp"
@@ -15,80 +18,179 @@ namespace gl::algorithm {
1518
1619// --- general types ---
1720
21+ // / @ingroup GL GL-Algorithm
22+ // / @brief A tag type used to explicitly indicate the absence of a callback function.
23+ // /
24+ // / > [!NOTE] Performance vs. Empty Lambdas
25+ // / >
26+ // / > Passing `empty_callback{}` is **not** the same as passing an empty lambda (e.g., `[]{}`).
27+ // / > Using this explicit tag type allows internal algorithms to use compile-time checks to
28+ // / > completely eliminate the callback invocation branch at compile time. This guarantees
29+ // / > strict zero-cost abstractions, vastly improves performance in unoptimized/debug builds,
30+ // / > and speeds up compilation times.
1831struct empty_callback {};
1932
33+ // / @ingroup GL GL-Algorithm GL-Types
34+ // / @brief Represents a generic tri-state decision for control flow.
35+ // /
36+ // / Used by custom predicates to determine how to proceed with a given item, execution step, or operation.
37+ // / While heavily utilized in graph traversal algorithms, it is entirely decoupled from graph-specific
38+ // / logic and can be used in any generic context requiring explicit accept/reject/abort semantics.
2039struct decision {
21- enum class eval : std::uint8_t { accept, reject, abort };
40+ // / @brief The underlying evaluation states.
41+ enum class eval : std::uint8_t {
42+ accept, // / < Proceed with the current element or operation.
43+ reject, // / < Skip the current element but continue the overall process.
44+ abort // / < Immediately terminate the entire process or algorithm.
45+ };
2246 using enum eval;
2347
48+ // / @brief Constructs a decision from an explicit evaluation state.
49+ // / @param value The tri-state evaluation.
2450 constexpr decision (const eval value) : value(value) {}
2551
52+ // / @brief Constructs a decision from a boolean value.
53+ // / @param value `true` maps to `accept`, `false` maps to `reject`.
2654 constexpr decision (const bool value) : value(value ? eval::accept : eval::reject) {}
2755
56+ // / @brief Assigns a boolean value to the decision.
57+ // / @param value `true` maps to `accept`, `false` maps to `reject`.
58+ // / @return A reference to this decision.
2859 constexpr decision& operator =(const bool value) {
2960 this ->value = value ? eval::accept : eval::reject;
3061 return *this ;
3162 }
3263
64+ // / @brief Evaluates the decision as a boolean.
65+ // / @return `true` if the decision is `accept`, `false` otherwise.
3366 [[nodiscard]] constexpr operator bool () const {
3467 return this ->value == eval::accept;
3568 }
3669
70+ // / @brief Compares the decision against a specific evaluation state.
71+ // / @param value The state to compare against.
72+ // / @return `true` if the states match.
3773 [[nodiscard]] constexpr bool operator ==(const eval value) const {
3874 return this ->value == value;
3975 }
4076
77+ // / @brief The stored evaluation state.
4178 eval value;
4279};
4380
44- enum class result_discriminator : bool { ret = true , noret = false };
81+ // / @ingroup GL GL-Algorithm
82+ // / @brief Tag used to statically dictate whether an algorithm should return a constructed result or execute purely for side effects.
83+ // /
84+ // / > [!NOTE] Namespace Availability
85+ // / >
86+ // / > Because this enum uses the `using enum` declaration, its members (`ret` and `noret`) are
87+ // / > injected directly into the `gl::algorithm` namespace. Hence, you can use `gl::algorithm::ret`
88+ // / > and `gl::algorithm::noret` directly without the `result_discriminator::` scope.
89+ // /
90+ // / ### See Also
91+ // / - @ref gl::algorithm::result_type "result_type"
92+ // / - @ref gl::algorithm::non_void_result_type "non_void_result_type"
93+ enum class result_discriminator : bool {
94+ ret = true , // / < The algorithm should build and return a result (e.g., a predecessor map).
95+ noret = false // / < The algorithm will purely invoke callbacks and return void.
96+ };
4597using enum result_discriminator;
4698
47- template <result_discriminator Result, typename ReturnType>
48- using return_type = std::conditional_t <Result == algorithm::ret, ReturnType, void >;
49-
50- template <result_discriminator Result, typename ReturnType>
51- using non_void_return_type =
52- std::conditional_t <Result == algorithm::ret, ReturnType, std::monostate>;
99+ // / @ingroup GL GL-Algorithm
100+ // / @brief Resolves to the specified `ResultType` if `Result` is `ret`, otherwise resolves to `void`.
101+ // /
102+ // / ### See Also
103+ // / - @ref gl::algorithm::result_discriminator "result_discriminator"
104+ // / - @ref gl::algorithm::non_void_result_type "non_void_result_type"
105+ template <result_discriminator Result, typename ResultType>
106+ using result_type = std::conditional_t <Result == algorithm::ret, ResultType, void >;
107+
108+ // / @ingroup GL GL-Algorithm
109+ // / @brief Resolves to the specified `ResultType` if `Result` is `ret`, otherwise resolves to `std::monostate`.
110+ // /
111+ // / Useful for returning dummy values from conditionally compiled algorithm branches.
112+ // /
113+ // / ### See Also
114+ // / - @ref gl::algorithm::result_discriminator "result_discriminator"
115+ // / - @ref gl::algorithm::result_type "result_type"
116+ template <result_discriminator Result, typename ResultType>
117+ using non_void_result_type =
118+ std::conditional_t <Result == algorithm::ret, ResultType, std::monostate>;
53119
54120// --- traversal types ---
55121
122+ // / @ingroup GL GL-Algorithm
123+ // / @brief Maps a vertex ID to its predecessor's ID in a traversal tree.
124+ // / @tparam GraphType The type of the graph being traversed.
56125template <traits::c_graph GraphType>
57126using predecessors_map = std::vector<typename GraphType::id_type>;
58127
128+ // / @ingroup GL GL-Algorithm
129+ // / @brief Represents an active node in a search frontier (e.g., a BFS queue or DFS stack).
130+ // / @tparam GraphType The type of the graph being searched.
59131template <traits::c_graph GraphType>
60132struct search_node {
61133 using id_type = typename GraphType::id_type;
62134
135+ // / @brief Constructs a search node acting as a root (predecessor is itself).
136+ // / @param vertex_id The ID of the vertex.
63137 search_node (id_type vertex_id) : vertex_id(vertex_id), pred_id(vertex_id) {}
64138
139+ // / @brief Constructs a search node with an explicit predecessor.
140+ // / @param vertex_id The ID of the vertex.
141+ // / @param pred_id The ID of the vertex's predecessor.
65142 search_node (id_type vertex_id, id_type pred_id) : vertex_id(vertex_id), pred_id(pred_id) {}
66143
144+ // / @brief Checks if this node is the root of a search tree.
145+ // / @return `true` if the node is valid and its predecessor is itself, `false` otherwise.
67146 [[nodiscard]] gl_attr_force_inline bool is_root () const noexcept {
68147 return this ->vertex_id != invalid_id and this ->vertex_id == this ->pred_id ;
69148 }
70149
150+ // / @brief The ID of the vertex currently being searched.
71151 id_type vertex_id;
152+ // / @brief The ID of the predecessor from which this vertex was reached.
72153 id_type pred_id;
73154};
74155
75156// --- constants ---
76157
158+ // / @ingroup GL GL-Algorithm
159+ // / @brief Constant representing the absence of a root vertex ID for a specific ID type.
160+ // /
161+ // / ### See Also
162+ // / - @ref gl::invalid_id_v "gl::invalid_id_v"
163+ // / - @ref gl::algorithm::no_root_t "no_root_t"
164+ // / - @ref gl::algorithm::no_root "no_root"
77165template <traits::c_id_type IdType>
78166inline constexpr IdType no_root_v = invalid_id_v<IdType>;
79167
168+ // / @ingroup GL GL-Algorithm
169+ // / @brief Tag type providing an implicit conversion to the appropriate `no_root_v` for any numeric ID type.
170+ // /
171+ // / ### See Also
172+ // / - @ref gl::algorithm::no_root_v "no_root_v"
173+ // / - @ref gl::algorithm::no_root "no_root"
80174struct no_root_t {
175+ // / @brief Implicitly converts to the numeric `no_root_v` constant.
81176 template <traits::c_id_type IdType>
82177 [[nodiscard]] constexpr operator IdType () const noexcept {
83178 return no_root_v<IdType>;
84179 }
85180
181+ // / @brief Checks if a given ID matches the `no_root_v` constant.
86182 template <traits::c_id_type IdType>
87183 [[nodiscard]] friend constexpr bool operator ==(const IdType& lhs, no_root_t ) noexcept {
88184 return lhs == no_root_v<IdType>;
89185 }
90186};
91187
188+ // / @ingroup GL GL-Algorithm
189+ // / @brief Global constant representing the absence of a root vertex.
190+ // /
191+ // / ### See Also
192+ // / - @ref gl::algorithm::no_root_v "no_root_v"
193+ // / - @ref gl::algorithm::no_root_t "no_root_t"
92194inline constexpr no_root_t no_root{};
93195
94196} // namespace gl::algorithm
0 commit comments