From 3be0136901069a50cf12d21bea49950f5a43dec6 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Wed, 14 Sep 2022 15:35:13 +0200 Subject: [PATCH] base: add util/dictionary.h utility The new 'Dictionary' provides an easy way to access objects using strings as key. The 'String' received the 'operator >' to simplify the organization of strings in an AVL tree. The patch removes the former definition of the 'operator >' from the platform driver because it would be ambigious now. Fixes #4610 --- repos/base/include/util/dictionary.h | 148 ++++++++++++++++++ repos/base/include/util/string.h | 6 + .../src/app/trace_recorder/named_registry.h | 6 - repos/os/src/drivers/platform/types.h | 6 - 4 files changed, 154 insertions(+), 12 deletions(-) create mode 100644 repos/base/include/util/dictionary.h diff --git a/repos/base/include/util/dictionary.h b/repos/base/include/util/dictionary.h new file mode 100644 index 0000000000..c393b0776c --- /dev/null +++ b/repos/base/include/util/dictionary.h @@ -0,0 +1,148 @@ +/* + * \brief Utility for accessing objects by name + * \author Norman Feske + * \date 2022-09-14 + */ + +/* + * Copyright (C) 2022 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__UTIL__DICTIONARY_H_ +#define _INCLUDE__UTIL__DICTIONARY_H_ + +#include +#include +#include +#include +#include + +namespace Genode { template class Dictionary; } + + +template +class Genode::Dictionary : Noncopyable +{ + private: + + Avl_tree _tree { }; + + public: + + class Element : private Avl_node + { + public: + + NAME const name; + + private: + + using This = Dictionary::Element; + + Dictionary &_dictionary; + + bool higher(T const *other) const { return name > other->This::name; } + + friend class Avl_tree; + friend class Avl_node; + friend class Dictionary; + + static T *_matching_sub_tree(T &curr, NAME const &name) + { + typename Avl_node::Side side = (curr.This::name > name); + return curr.Avl_node::child(side); + } + + public: + + Element(Dictionary &dictionary, NAME const &name) + : + name(name), _dictionary(dictionary) + { + if (_dictionary.exists(name)) + warning("dictionary entry '", name, "' is not unique"); + + _dictionary._tree.insert(this); + } + + ~Element() + { + _dictionary._tree.remove(this); + } + }; + + /** + * Call 'match_fn' with named constant dictionary element + * + * The 'match_fn' functor is called with a const reference to the + * matching dictionary element. If no maching element exists, + * 'no_match_fn' is called without argument. + */ + template + auto with_element(NAME const &name, FN1 const &match_fn, FN2 const &no_match_fn) + -> typename Trait::Functor::Return_type + { + T *curr_ptr = _tree.first(); + for (;;) { + if (!curr_ptr) + break; + + if (curr_ptr->Element::name == name) { + return match_fn(*curr_ptr); + } + + curr_ptr = Element::_matching_sub_tree(*curr_ptr, name); + } + return no_match_fn(); + } + + /** + * Call 'match_fn' with named mutable dictionary element + * + * The 'match_fn' functor is called with a non-const reference to the + * matching dictionary element. If no maching element exists, + * 'no_match_fn' is called without argument. + */ + template + auto with_element(NAME const &name, FN1 const &match_fn, FN2 const &no_match_fn) const + -> typename Trait::Functor::Return_type + { + auto const_match_fn = [&] (T const &e) { return match_fn(e); }; + auto non_const_this = const_cast(this); + return non_const_this->with_element(name, const_match_fn, no_match_fn); + } + + /** + * Call 'fn' with a non-const reference to any dictionary element + * + * \return true if 'fn' was called, or + * false if the dictionary is empty + * + * This method is intended for the orderly destruction of a dictionary. + * It allows for the consecutive destruction of all elements. + */ + template + bool with_any_element(FUNC const &fn) + { + T *curr_ptr = _tree.first(); + if (!curr_ptr) + return false; + + fn(*curr_ptr); + return true; + } + + template + void for_each(FN const &fn) const { _tree.for_each(fn); } + + bool exists(NAME const &name) const + { + return with_element(name, [] (T const &) { return true; }, + [] { return false; }); + } +}; + +#endif /* _INCLUDE__UTIL__DICTIONARY_H_ */ diff --git a/repos/base/include/util/string.h b/repos/base/include/util/string.h index f82fbabacb..5eb4eb2162 100644 --- a/repos/base/include/util/string.h +++ b/repos/base/include/util/string.h @@ -808,6 +808,12 @@ class Genode::String return strcmp(string(), other.string()) != 0; } + template + bool operator > (String const &other) const + { + return strcmp(string(), other.string()) > 0; + } + void print(Output &out) const { Genode::print(out, string()); } }; diff --git a/repos/gems/src/app/trace_recorder/named_registry.h b/repos/gems/src/app/trace_recorder/named_registry.h index 51e29f98b1..ea5c07047c 100644 --- a/repos/gems/src/app/trace_recorder/named_registry.h +++ b/repos/gems/src/app/trace_recorder/named_registry.h @@ -22,12 +22,6 @@ namespace Trace_recorder { using namespace Genode; template class Named_registry; - - template - static inline bool operator > (String const &s1, String const &s2) - { - return strcmp(s1.string(), s2.string()) > 0; - } } template diff --git a/repos/os/src/drivers/platform/types.h b/repos/os/src/drivers/platform/types.h index 788aac18ee..54b93f8f93 100644 --- a/repos/os/src/drivers/platform/types.h +++ b/repos/os/src/drivers/platform/types.h @@ -20,12 +20,6 @@ namespace Driver { using namespace Genode; - template - static inline bool operator > (String const &s1, String const &s2) - { - return strcmp(s1.string(), s2.string()) > 0; - } - /** * Utility for switching clocks/resets/powers on/off depending on the * number of users