LCOV - code coverage report
Current view: top level - src/bindings/cpp/examples - cpp_example_hierarchy.cpp (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 0 91 0.0 %
Date: 2022-05-21 16:19:22 Functions: 0 6 0.0 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief
       5             :  *
       6             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
       7             :  */
       8             : 
       9             : #include <keyset.hpp>
      10             : 
      11             : #include <cassert>
      12             : #include <iostream>
      13             : #include <map>
      14             : #include <string>
      15             : 
      16             : namespace kdb
      17             : {
      18             : 
      19             : /**
      20             :  * @brief Search for nth level in a name
      21             :  *
      22             :  * @param k the key to search in
      23             :  * @param n the level
      24             :  *
      25             :  * nth_level_of_name(Key("user:/hello", KEY_END), 0) -> "user:"
      26             :  * nth_level_of_name(Key("user:/hello", KEY_END), 1) -> "hello"
      27             :  *
      28             :  * @return the searched string (without slashes)
      29             :  */
      30           0 : std::string nth_level_of_name (Key k, unsigned long n)
      31             : {
      32           0 :         size_t prev = 0;
      33           0 :         std::string name = k.getName ();
      34             : 
      35           0 :         for (unsigned long i = 0; i < n; ++i)
      36             :         {
      37           0 :                 size_t pos = name.find ("/", prev);
      38           0 :                 prev = pos + 1;
      39             :         }
      40             : 
      41           0 :         return name.substr (prev, name.find ("/", prev) - prev);
      42             : }
      43             : 
      44             : /**
      45             :  * @brief The number of levels a name has
      46             :  *
      47             :  * @param k the key to search within
      48             :  *
      49             :  * @return the hierarchy depth of a key
      50             :  */
      51           0 : unsigned long name_depth (Key k)
      52             : {
      53           0 :         std::string name = k.getName ();
      54           0 :         size_t pos = name.find ("/", 0);
      55           0 :         unsigned long depth = 0;
      56             : 
      57           0 :         while (pos != std::string::npos)
      58             :         {
      59           0 :                 pos = name.find ("/", pos + 1);
      60           0 :                 ++depth;
      61             :         }
      62             : 
      63           0 :         return depth;
      64             : }
      65             : 
      66             : /**
      67             :  * @brief Visitor (of Visitor pattern)
      68             :  */
      69             : class Visitor
      70             : {
      71             : public:
      72             :         virtual void visit (std::string name, unsigned long depth, Key k) = 0;
      73             : };
      74             : 
      75             : class KeyHierarchy;
      76             : 
      77             : /**
      78             :  * @brief A KeyNode builds up the structure of the KeyHierarchy
      79             :  *
      80             :  * Every KeyNode contains children (subnodes).
      81             :  * KeyNodes that are for structure only, do not contain a Key (0-key)
      82             :  * other KeyNodes have a reference to a key
      83             :  */
      84           0 : class KeyNode
      85             : {
      86             : public:
      87             :         typedef std::map<std::string, KeyNode> KeyNodeMap;
      88             :         typedef KeyNodeMap::iterator KeyNodeIterator;
      89             : 
      90           0 :         KeyNode (unsigned long depth, Key k = static_cast<ckdb::Key *> (nullptr)) : m_self (k), m_subnodes (), m_depth (depth)
      91             :         {
      92             :         }
      93             : 
      94             :         /**
      95             :          * @brief (Recursively) add or update a key to nodes
      96             :          *
      97             :          * If the key exists, it will be updated
      98             :          *
      99             :          * If the key does not exist, node(s) will be created
     100             :          *
     101             :          * @param k the key to add
     102             :          * @param depth current depth of recursion
     103             :          */
     104           0 :         void add (Key k, unsigned long depth)
     105             :         {
     106           0 :                 assert (k);
     107           0 :                 assert (m_self ? m_self.isBelow (k) : true);
     108           0 :                 depth++;
     109             : 
     110           0 :                 if (m_self.isDirectBelow (k) || depth == name_depth (k))
     111             :                 {
     112           0 :                         for (auto & elem : m_subnodes)
     113             :                         {
     114           0 :                                 if (elem.first == k.getBaseName ())
     115             :                                 {
     116             :                                         // found node, update it
     117           0 :                                         elem.second.m_self = k;
     118           0 :                                         return;
     119             :                                 }
     120             :                         }
     121             :                         // will add new subnode (direct below+not found)
     122           0 :                         m_subnodes.insert (std::make_pair (k.getBaseName (), KeyNode (depth, k)));
     123           0 :                         return;
     124             :                 }
     125             : 
     126           0 :                 for (auto & elem : m_subnodes)
     127             :                 {
     128           0 :                         if (k.isBelow (elem.second.m_self))
     129             :                         {
     130             :                                 // found subnode, call recursively
     131           0 :                                 elem.second.add (k, depth);
     132           0 :                                 return;
     133             :                         }
     134             :                 }
     135             : 
     136             :                 // create a structure key (without key, only name)
     137           0 :                 std::string name = nth_level_of_name (k, depth);
     138           0 :                 std::pair<KeyNodeIterator, bool> p = m_subnodes.insert (std::make_pair (name, KeyNode (depth)));
     139             :                 // structure keys get a null key
     140           0 :                 auto it = p.first;
     141           0 :                 it->second.add (k, depth);
     142             :         }
     143             : 
     144             :         /**
     145             :          * @brief Accept a visitor for iteration
     146             :          *
     147             :          * @param visitor defines the action
     148             :          */
     149           0 :         void accept (Visitor & visitor)
     150             :         {
     151           0 :                 for (auto & elem : m_subnodes)
     152             :                 {
     153           0 :                         visitor.visit (elem.first, elem.second.m_depth, elem.second.m_self);
     154           0 :                         elem.second.accept (visitor);
     155             :                 }
     156           0 :         }
     157             : 
     158             : private:
     159             :         friend class KeyHierarchy; // they are tightly coupled
     160             : 
     161             :         Key m_self;
     162             :         KeyNodeMap m_subnodes;
     163             :         unsigned long m_depth;
     164             : };
     165             : 
     166             : /**
     167             :  * @brief Builds up a hierarchy of Keys
     168             :  *
     169             :  * Also keeps a KeySet in sync with what is in the hierarchy.
     170             :  * The keys will be shared between the keyset and the hierarchy.
     171             :  */
     172           0 : class KeyHierarchy
     173             : {
     174             : public:
     175           0 :         explicit KeyHierarchy (KeySet & keyset) : m_userRootNode (0), m_systemRootNode (0), m_keyset (keyset)
     176             :         {
     177           0 :                 add (keyset);
     178           0 :         }
     179             : 
     180             :         /**
     181             :          * @brief Add all keys of a keyset
     182             :          *
     183             :          * Will not update the underlying keyset (is fixed at
     184             :          * construction)
     185             :          *
     186             :          * @param ks
     187             :          */
     188           0 :         void add (KeySet const & ks)
     189             :         {
     190           0 :                 for (auto && k : ks)
     191             :                 {
     192           0 :                         add (k);
     193             :                 }
     194           0 :         }
     195             : 
     196             :         /**
     197             :          * @brief Add a single key to hierarchy
     198             :          *
     199             :          * @param k the key to add
     200             :          */
     201           0 :         void add (Key k)
     202             :         {
     203             :                 // update root nodes
     204           0 :                 if (k.getName () == "user:/")
     205             :                 {
     206           0 :                         m_userRootNode.m_self = k;
     207             :                 }
     208           0 :                 else if (k.getName () == "system:/")
     209             :                 {
     210           0 :                         m_systemRootNode.m_self = k;
     211             :                 }
     212             :                 // if it is not a root node, update hierarchy
     213           0 :                 else if (k.isUser ())
     214             :                 {
     215           0 :                         m_userRootNode.add (k, 0);
     216             :                 }
     217             :                 else
     218             :                 {
     219           0 :                         m_systemRootNode.add (k, 0);
     220             :                 }
     221             : 
     222             :                 // update keyset
     223           0 :                 m_keyset.lookup (k, KDB_O_POP);
     224           0 :                 m_keyset.append (k);
     225           0 :         }
     226             : 
     227             :         /**
     228             :          * @brief Allow visitor to traverse the hierarchy
     229             :          *
     230             :          * @param visitor to traverse
     231             :          */
     232           0 :         void accept (Visitor & visitor)
     233             :         {
     234           0 :                 visitor.visit ("user:/", 0, m_userRootNode.m_self);
     235           0 :                 m_userRootNode.accept (visitor);
     236           0 :                 visitor.visit ("system:/", 0, m_systemRootNode.m_self);
     237           0 :                 m_systemRootNode.accept (visitor);
     238           0 :         }
     239             : 
     240             : private:
     241             :         KeyNode m_userRootNode;
     242             :         KeyNode m_systemRootNode;
     243             : 
     244             :         KeySet & m_keyset;
     245             : };
     246             : } // namespace kdb
     247             : 
     248             : 
     249             : /**
     250             :  * @brief Example visitor that prints the hierarchy
     251             :  */
     252             : class PrintVisitor : public kdb::Visitor
     253             : {
     254             : public:
     255           0 :         void visit (std::string name, unsigned long depth, kdb::Key k) override
     256             :         {
     257           0 :                 for (unsigned long i = 0; i < depth; ++i)
     258             :                 {
     259           0 :                         std::cout << "   ";
     260             :                 }
     261             : 
     262           0 :                 std::cout << name;
     263             : 
     264           0 :                 if (k)
     265             :                 {
     266           0 :                         std::cout << "(" << k.getName () << ") = " << k.getString ();
     267             :                 }
     268             : 
     269           0 :                 std::cout << std::endl;
     270           0 :         }
     271             : };
     272             : 
     273           0 : int main ()
     274             : {
     275           0 :         using namespace kdb;
     276           0 :         KeySet ks;
     277           0 :         KeyHierarchy kh (ks);
     278           0 :         kh.add (Key ("user:/hello", KEY_VALUE, "Hello world", KEY_END));
     279           0 :         PrintVisitor pv;
     280           0 :         kh.accept (pv);
     281           0 :         std::cout << std::endl;
     282             : 
     283           0 :         kh.add (Key ("system:/b/s/t", KEY_VALUE, "Below", KEY_END));
     284           0 :         kh.accept (pv);
     285           0 :         std::cout << std::endl;
     286             : 
     287           0 :         kh.add (Key ("system:/b/s/t", KEY_VALUE, "Updated", KEY_END));
     288           0 :         kh.accept (pv);
     289           0 :         std::cout << std::endl;
     290             : 
     291           0 :         kh.add (Key ("system:/", KEY_VALUE, "root value", KEY_END));
     292           0 :         kh.accept (pv);
     293           0 : }

Generated by: LCOV version 1.13