Skip to content

Commit e633749

Browse files
amabluea-maurice
authored andcommitted
Added additional utility functions to Tree<T>.
PiperOrigin-RevId: 280241417
1 parent 70da363 commit e633749

File tree

1 file changed

+132
-1
lines changed
  • database/src/desktop/core

1 file changed

+132
-1
lines changed

database/src/desktop/core/tree.h

Lines changed: 132 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@
1111
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
14-
1514
#ifndef FIREBASE_DATABASE_CLIENT_CPP_SRC_DESKTOP_CORE_TREE_H_
1615
#define FIREBASE_DATABASE_CLIENT_CPP_SRC_DESKTOP_CORE_TREE_H_
1716

1817
#include <map>
1918
#include <string>
19+
2020
#include "app/src/optional.h"
2121
#include "app/src/path.h"
2222
#include "database/src/desktop/util_desktop.h"
@@ -151,6 +151,137 @@ class Tree {
151151
return SetValueAt(path, Optional<Value>(std::move(value)));
152152
}
153153

154+
// Returns the root-most element in the tree in the given path. For example,
155+
// if a Tree<int> contains the following values:
156+
//
157+
// -+ <root>: None
158+
// |
159+
// +- "Foo": None
160+
// | |
161+
// | +- "Bar": 100
162+
// | |
163+
// | +- "Baz": 200
164+
// |
165+
// +- "quux": 300
166+
//
167+
// And the path given is "foo/bar/baz", then the return value will be a
168+
// pointer to 100, because that is the root-most value in the given path. If
169+
// a value cannot be found then nullptr is returned.
170+
const Value* RootMostValue(const Path& path) const {
171+
return RootMostValueMatching(path, [](const Value& value) { return true; });
172+
}
173+
174+
// Returns the root-most element in the tree in the given path that matches
175+
// the given predicate. For example, if a Tree<int> contains the following
176+
// values:
177+
//
178+
// -+ <root>: 0
179+
// |
180+
// +- "Foo": 50
181+
// | |
182+
// | +- "Bar": 100
183+
// | |
184+
// | +- "Baz": 200
185+
// |
186+
// +- "quux": 300
187+
//
188+
// And the path given is "foo/bar/baz", and the predicate is value > 75, then
189+
// the return value will be a pointer to 100, because that is the root-most
190+
// value in the given path that meets the condition given.
191+
template <typename Func>
192+
const Value* RootMostValueMatching(const Path& path,
193+
const Func& predicate) const {
194+
if (value_.has_value() && predicate(*value_)) {
195+
return &value_.value();
196+
} else {
197+
const Tree<Value>* current_tree = this;
198+
for (const std::string& directory : path.GetDirectories()) {
199+
current_tree = current_tree->GetChild(directory);
200+
if (current_tree == nullptr) {
201+
return nullptr;
202+
} else if (current_tree->value_.has_value() &&
203+
predicate(*current_tree->value_)) {
204+
return &current_tree->value_.value();
205+
}
206+
}
207+
return nullptr;
208+
}
209+
}
210+
211+
// Returns the leaf-most element in the tree in the given path. For example,
212+
// if a Tree<int> contains the following values:
213+
//
214+
// -+ <root>: None
215+
// |
216+
// +- "Foo": 200
217+
// | |
218+
// | +- "Bar": 100
219+
// | |
220+
// | +- "Baz": None
221+
// |
222+
// +- "quux": 300
223+
//
224+
// And the path given is "foo/bar/baz", then the return value will be a
225+
// pointer to 100, because that is the leaf-most value in the given path. If
226+
// a value cannot be found then nullptr is returned.
227+
const Value* LeafMostValue(const Path& path) const {
228+
return LeafMostValueMatching(path, [](const Value& value) { return true; });
229+
}
230+
231+
// Returns the leaf-most element in the tree in the given path that matches
232+
// the given predicate. For example, if a Tree<int> contains the following
233+
// values:
234+
//
235+
// -+ <root>: 200
236+
// |
237+
// +- "Foo": 100
238+
// | |
239+
// | +- "Bar": 50
240+
// | |
241+
// | +- "Baz": 0
242+
// |
243+
// +- "quux": 300
244+
//
245+
// And the path given is "foo/bar/baz", and the predicate is value > 75, then
246+
// the return value will be a pointer to 100, because that is the leaf-most
247+
// value in the given path that meets the condition given.
248+
template <typename Func>
249+
const Value* LeafMostValueMatching(const Path& path,
250+
const Func& predicate) const {
251+
const Value* current_value =
252+
(value_.has_value() && predicate(*value_)) ? &value_.value() : nullptr;
253+
const Tree<Value>* current_tree = this;
254+
for (const std::string& directory : path.GetDirectories()) {
255+
current_tree = current_tree->GetChild(directory);
256+
if (current_tree == nullptr) {
257+
return current_value;
258+
} else {
259+
if (current_tree->value_.has_value() &&
260+
predicate(*current_tree->value_)) {
261+
current_value = &current_tree->value_.value();
262+
}
263+
}
264+
}
265+
return current_value;
266+
}
267+
268+
// Returns true if any location at or beneath this location in the tree meets
269+
// the criteria given by the predicate.
270+
template <typename Func>
271+
bool ContainsMatchingValue(const Func& predicate) const {
272+
if (value_.has_value() && predicate(*value_)) {
273+
return true;
274+
} else {
275+
for (auto& key_subtree_pair : children_) {
276+
const Tree<Value>& subtree = key_subtree_pair.second;
277+
if (subtree.ContainsMatchingValue(predicate)) {
278+
return true;
279+
}
280+
}
281+
return false;
282+
}
283+
}
284+
154285
// Get a child node using the given key.
155286
Tree<Value>* GetChild(const std::string& key) {
156287
if (key.empty()) {

0 commit comments

Comments
 (0)