Simo 0.0.1
Loading...
Searching...
No Matches
ParameterTrie.h
1// Copyright 2026 Matteo Fusi and Contributors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#ifndef SIMO_PARAMETERTRIE_HH
16#define SIMO_PARAMETERTRIE_HH
17
18#include <Simo/compiler/BoostTypeIndexRuntimeCast.h>
19#include <Simo/compiler/Compiler.h>
20
21#include <ranges>
22#include <string_view>
23#include <unordered_map>
24
25#include "Parameter.h"
26
27namespace Simo::Parameter {
28class Parameter;
29constexpr char PARAMETER_NODE_SEPARATOR = '/';
30
35class SIMO_PUBLIC ParameterTrie {
36 static constexpr std::pair<std::string_view, std::string_view>
37 split_string_view(const std::string_view name) {
38 const auto next_dot_pos = name.find(PARAMETER_NODE_SEPARATOR);
39 if (next_dot_pos == std::string_view::npos) {
40 return std::make_pair(name, std::string_view{});
41 }
42 return std::make_pair(name.substr(0, next_dot_pos),
43 name.substr(next_dot_pos + 1));
44 }
45
46 public:
47 ParameterTrie() = default;
48
49 ParameterTrie(const ParameterTrie& other) { *this = other; }
50
51 ParameterTrie& operator=(const ParameterTrie& other) {
52 if (other.value) {
53 value = std::unique_ptr(other.value->clone());
54 }
55 for (const auto& [fst, snd] : other.children) {
56 children[fst] = snd;
57 }
58 return *this;
59 }
60
61 template <typename T, typename... Args>
62 [[maybe_unused]]
63 ParameterTyped<T>& add(const std::string_view name, Args... args) {
64 return add_generic<T>(name, true, std::forward<Args>(args)...);
65 }
66
67 template <typename T>
68 [[maybe_unused]]
69 ParameterTyped<T>& add_unset(const std::string_view name) {
70 return add_generic<T>(name, false);
71 }
72
73 [[nodiscard]]
74 Parameter* find(const std::string_view name) const {
75 if (name.empty()) {
76 return value.get();
77 }
78 const auto [child_name, rest_of_name] = split_string_view(name);
79 if (!children.contains(std::string(child_name))) {
80 return nullptr;
81 }
82 return children.at(std::string(child_name)).find(rest_of_name);
83 }
84
85 template <typename T>
86 [[nodiscard]] ParameterTyped<T>* find(const std::string_view name) const {
87 auto* const res = find(name);
88 return res == nullptr
89 ? nullptr
90 : boost::typeindex::runtime_cast<ParameterTyped<T>*>(res);
91 }
92
93 [[nodiscard]] const ParameterTrie* get_subtrie(
94 const std::string_view name) const {
95 if (name.empty()) {
96 return this;
97 }
98 const auto [child_name, rest_of_name] = split_string_view(name);
99 if (!children.contains(std::string(child_name))) {
100 return nullptr;
101 }
102 return children.at(std::string(child_name)).get_subtrie(rest_of_name);
103 }
104
107 template <typename Function>
108 [[nodiscard]]
109 bool all(Function f) const {
110 if (value != nullptr && !f(*value)) {
111 return false;
112 }
113 for (const auto& snd : children | std::views::values) {
114 if (!snd.all(f)) {
115 return false;
116 }
117 }
118 return true;
119 }
120
123 template <typename Function>
124 void visit(Function f) const {
125 visit_impl("", f);
126 }
127
128 template <typename Function>
129 void visit_impl(std::string_view name, Function f) const {
130 if (value != nullptr) {
131 if (!value->has_value()) {
132 f(name, nullptr);
133 } else {
134 f(name, value.get());
135 }
136 }
137 for (const auto& [child_name, sub_tree] : children) {
138 std::string sub_tree_name =
139 (name.empty() ? "" : std::string(name) + PARAMETER_NODE_SEPARATOR) +
140 child_name;
141 sub_tree.visit_impl(sub_tree_name, f);
142 }
143 }
144
145 std::unique_ptr<Parameter> value;
146
147 protected:
148 template <typename T, typename... Args>
149 [[nodiscard]]
150 ParameterTyped<T>& add_generic(const std::string_view name, bool has_value,
151 Args&&... args) {
152 if (name.empty()) {
153 auto ptr = new ParameterTyped<T>(std::forward<Args>(args)...);
154 value = std::unique_ptr<Parameter>(ptr);
155 value->has_value(has_value);
156 return *ptr;
157 }
158 const auto [child_name, rest_of_name] = split_string_view(name);
159 return children[std::string(child_name)].add_generic<T>(
160 rest_of_name, has_value, std::forward<Args>(args)...);
161 }
162
163 private:
164 std::unordered_map<std::string, ParameterTrie> children;
165};
166} // namespace Simo::Parameter
167
168#endif // SIMO_PARAMETERTRIE_HH
bool all(Function f) const
Definition ParameterTrie.h:109
void visit(Function f) const
Definition ParameterTrie.h:124
A Parameter with a type.
Definition Parameter.h:74
Base class for any Parameter.
Definition Parameter.h:31