LCOV - code coverage report
Current view: top level - src/bindings/cpp/include - kdbvalue.hpp (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 145 149 97.3 %
Date: 2019-09-12 12:28:41 Functions: 148 250 59.2 %

          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             : #ifndef ELEKTRA_KDBVALUE_HPP
      10             : #define ELEKTRA_KDBVALUE_HPP
      11             : 
      12             : #include <kdbmacros.h>
      13             : 
      14             : #ifdef HAVE_KDBCONFIG_H
      15             : #include <kdbconfig.h>
      16             : #else
      17             : #define DEBUG 0
      18             : #define VERBOSE 0
      19             : #endif
      20             : 
      21             : #include <algorithm>
      22             : #include <cassert>
      23             : #include <fstream>
      24             : #include <functional>
      25             : #include <iostream>
      26             : #include <kdbmeta.h>
      27             : #include <map>
      28             : #include <memory>
      29             : #include <set>
      30             : #include <stdexcept>
      31             : #include <string>
      32             : #include <unordered_map>
      33             : #include <vector>
      34             : 
      35             : #include <kdbproposal.h>
      36             : #include <keyset.hpp>
      37             : 
      38             : // #include <kdbprivate.h> // for debugging (to see values of internal structures)
      39             : 
      40             : namespace kdb
      41             : {
      42             : 
      43             : 
      44             : // some widely used interfaces
      45             : 
      46             : /**
      47             :  * @brief This type is being used as bottom type that always fails.
      48             :  */
      49             : class none_t
      50             : {
      51             : };
      52             : 
      53             : template <>
      54             : inline void Key::set (none_t)
      55             : {
      56             : }
      57             : 
      58             : template <>
      59             : inline none_t Key::get () const
      60             : {
      61             :         none_t ret;
      62             :         return ret;
      63             : }
      64             : 
      65             : 
      66             : /**
      67             :  * @brief Base class for all layers.
      68             :  */
      69             : class Layer
      70             : {
      71             : public:
      72             :         virtual ~Layer (){};
      73             :         virtual std::string id () const = 0;
      74             :         virtual std::string operator() () const = 0;
      75             : };
      76             : 
      77             : /**
      78             :  * @brief Everything implementing this interface can be used as layer
      79             :  *
      80             :  * Different from "Layer" objects they will not be constructed on activation
      81             :  * but instead only the WrapLayer will be constructed and the wrapped object
      82             :  * will be passed along by reference.
      83             :  *
      84             :  * @note the lifetime must be beyond layer deactivation!
      85             :  */
      86           6 : class Wrapped
      87             : {
      88             : public:
      89           0 :         virtual ~Wrapped (){};
      90             :         virtual std::string layerId () const = 0;
      91             :         virtual std::string layerVal () const = 0;
      92             : };
      93             : 
      94             : class WrapLayer : public Layer
      95             : {
      96             : public:
      97          40 :         explicit WrapLayer (Wrapped const & wrapped) : m_wrapped (wrapped)
      98             :         {
      99             :         }
     100             : 
     101          38 :         virtual ~WrapLayer (){};
     102             : 
     103         152 :         virtual std::string id () const
     104             :         {
     105         152 :                 return m_wrapped.layerId ();
     106             :         }
     107             : 
     108          96 :         virtual std::string operator() () const
     109             :         {
     110          96 :                 return m_wrapped.layerVal ();
     111             :         }
     112             : 
     113             : private:
     114             :         Wrapped const & m_wrapped;
     115             : };
     116             : 
     117             : class KeyValueLayer : public kdb::Layer
     118             : {
     119             : public:
     120         204 :         KeyValueLayer (std::string key, std::string value) : m_key (std::move (key)), m_value (std::move (value))
     121             :         {
     122          68 :         }
     123             : 
     124         162 :         virtual ~KeyValueLayer (){};
     125             : 
     126         200 :         std::string id () const override
     127             :         {
     128         400 :                 return m_key;
     129             :         }
     130         300 :         std::string operator() () const override
     131             :         {
     132         600 :                 return m_value;
     133             :         }
     134             : 
     135             : private:
     136             :         std::string m_key;
     137             :         std::string m_value;
     138             : };
     139             : 
     140             : /**
     141             :  * @brief Base class for values to be observed.
     142             :  *
     143             :  * updateContext() is called whenever a context tells a value that it
     144             :  * should reevaluate its name and update its cache.
     145             :  */
     146           6 : class ValueObserver
     147             : {
     148             : public:
     149             :         virtual ~ValueObserver () = 0;
     150             :         virtual void updateContext (bool write = true) const = 0;
     151             :         virtual kdb::Key getDepKey () const = 0;
     152             : 
     153             :         typedef std::reference_wrapper<ValueObserver> reference;
     154             : };
     155             : 
     156             : /**
     157             :  * @brief Needed to put a ValueObserver in a map
     158             :  *
     159             :  * @return Comparison result
     160             :  */
     161             : inline bool operator< (ValueObserver const & lhs, ValueObserver const & rhs)
     162             : {
     163         200 :         return &lhs < &rhs;
     164             : }
     165             : 
     166           0 : inline ValueObserver::~ValueObserver ()
     167             : {
     168             : }
     169             : 
     170             : 
     171           6 : class ValueSubject
     172             : {
     173             : public:
     174             :         virtual void notifyInThread () = 0;
     175             : };
     176             : 
     177             : /**
     178             :  * @brief Used by contexts for callbacks (to run code using a mutex).
     179             :  *
     180             :  * Following scenarios are possible:
     181             :  * !oldName && !newName: execute code, do nothing else
     182             :  * !oldName && newName: attach
     183             :  * oldName && newName: reattach
     184             :  * oldName == newName: assignment, attach for inter-thread updates
     185             :  * oldName && !newName: detach
     186             :  */
     187        2874 : struct Command
     188             : {
     189             : public:
     190             :         typedef std::pair<std::string, std::string> Pair;
     191             :         /**
     192             :          * @brief Typedef for function that returns oldKey, newKey pair
     193             :          */
     194             :         typedef std::function<Pair ()> Func;
     195             :         Command (ValueSubject const & v_, Func & execute_, bool hasChanged_ = false)
     196        2874 :         : v (const_cast<ValueSubject &> (v_)), execute (execute_), hasChanged (hasChanged_), oldKey (), newKey ()
     197             :         {
     198             :         }
     199             : 
     200             :         Pair operator() ()
     201             :         {
     202        1916 :                 return execute ();
     203             :         }
     204             : 
     205             :         ValueSubject & v;   // this pointer
     206             :         Func & execute;     // to be executed within lock
     207             :         bool hasChanged;    // if the value (m_cache) has changed and value propagation is needed
     208             :         std::string oldKey; // old name before assignment
     209             :         std::string newKey; // new name after assignment
     210             : };
     211             : 
     212             : // Default Policies for Value
     213             : 
     214             : class NoContext
     215             : {
     216             : public:
     217             :         /**
     218             :          * @brief attach a new value
     219             :          *
     220             :          * NoContext will never update anything
     221             :          */
     222             :         void attachByName (ELEKTRA_UNUSED std::string const & key_name, ELEKTRA_UNUSED ValueObserver & ValueObserver)
     223             :         {
     224             :         }
     225             : 
     226             :         /**
     227             :          * @brief The evaluated equals the non-evaluated name!
     228             :          *
     229             :          * @return NoContext always returns the same string
     230             :          */
     231             :         std::string evaluate (std::string const & key_name) const
     232             :         {
     233           8 :                 return key_name;
     234             :         }
     235             : 
     236             :         std::string evaluate (std::string const & key_name,
     237             :                               std::function<bool(std::string const &, std::string &, bool in_group)> const &) const
     238             :         {
     239           0 :                 return key_name;
     240             :         }
     241             : 
     242             :         /**
     243             :          * @brief (Re)attaches a ValueSubject to a thread or simply
     244             :          *        execute code in a locked section.
     245             :          *
     246             :          * NoContext just executes the function and does not
     247             :          * attach/reattach/detach
     248             :          *
     249             :          * @param c the command to apply
     250             :          */
     251          58 :         void execute (Command & c)
     252             :         {
     253         116 :                 c ();
     254          58 :         }
     255             : };
     256             : 
     257             : /**
     258             :  * @brief Implements lookup with spec.
     259             :  */
     260             : class DefaultGetPolicy
     261             : {
     262             : public:
     263         544 :         static Key get (KeySet & ks, Key const & spec)
     264             :         {
     265         544 :                 return ks.lookup (spec, ckdb::KDB_O_SPEC | ckdb::KDB_O_CREATE);
     266             :         }
     267             : };
     268             : 
     269             : /**
     270             :  * @brief Implements creating user/ key when key is not found.
     271             :  */
     272             : class DefaultSetPolicy
     273             : {
     274             : public:
     275          94 :         static Key set (KeySet & ks, Key const & spec)
     276             :         {
     277         376 :                 return setWithNamespace (ks, spec, "user");
     278             :         }
     279             : 
     280          96 :         static Key setWithNamespace (KeySet & ks, Key const & spec, std::string const & ns)
     281             :         {
     282         192 :                 std::string const & name = spec.getName ();
     283             : 
     284         288 :                 kdb::Key k (ns + "/" + name, KEY_END);
     285          96 :                 ks.append (k);
     286             : 
     287          96 :                 return k;
     288             :         }
     289             : };
     290             : 
     291             : class DefaultWritePolicy
     292             : {
     293             : public:
     294             :         static const bool allowed = true;
     295             : };
     296             : 
     297             : class ReadOnlyPolicy
     298             : {
     299             : public:
     300             :         static const bool allowed = false;
     301             : };
     302             : 
     303             : class DefaultObserverPolicy
     304             : {
     305             : public:
     306             :         typedef double type;
     307             : };
     308             : 
     309             : class NoLockPolicy
     310             : {
     311             : public:
     312             :         void lock ()
     313             :         {
     314             :         }
     315             :         void unlock ()
     316             :         {
     317             :         }
     318             : };
     319             : 
     320             : /*
     321             :  * This technique with the PolicySelector and Discriminator is taken
     322             :  * from the book  "C++ Templates - The Complete Guide"
     323             :  * by David Vandevoorde and Nicolai M. Josuttis, Addison-Wesley, 2002
     324             :  * in Chapter 16 Templates and Inheritance: Named Template Arguments
     325             :  *
     326             :  * The technique allows users of the class Value to use any number
     327             :  * and order of policies as desired.
     328             :  */
     329             : 
     330             : 
     331             : template <typename Base, int D>
     332             : class Discriminator : public Base
     333             : {
     334             : };
     335             : 
     336             : template <typename Setter1, typename Setter2, typename Setter3, typename Setter4, typename Setter5, typename Setter6>
     337             : class PolicySelector : public Discriminator<Setter1, 1>,
     338             :                        public Discriminator<Setter2, 2>,
     339             :                        public Discriminator<Setter3, 3>,
     340             :                        public Discriminator<Setter4, 4>,
     341             :                        public Discriminator<Setter5, 5>,
     342             :                        public Discriminator<Setter6, 6>
     343             : {
     344             : };
     345             : 
     346             : class DefaultPolicies
     347             : {
     348             : public:
     349             :         typedef DefaultGetPolicy GetPolicy;
     350             :         typedef DefaultSetPolicy SetPolicy;
     351             :         typedef NoContext ContextPolicy;
     352             :         typedef DefaultWritePolicy WritePolicy;
     353             :         typedef DefaultObserverPolicy ObserverPolicy;
     354             :         typedef NoLockPolicy LockPolicy;
     355             : };
     356             : 
     357             : class DefaultPolicyArgs : virtual public DefaultPolicies
     358             : {
     359             : };
     360             : 
     361             : 
     362             : // class templates to override the default policy values
     363             : 
     364             : /// Needed by the user to set one of the policies
     365             : ///
     366             : /// @tparam Policy
     367             : template <typename Policy>
     368             : class GetPolicyIs : virtual public DefaultPolicies
     369             : {
     370             : public:
     371             :         typedef Policy GetPolicy;
     372             : };
     373             : 
     374             : 
     375             : /// Needed by the user to set one of the policies
     376             : ///
     377             : /// @tparam Policy
     378             : template <typename Policy>
     379             : class SetPolicyIs : virtual public DefaultPolicies
     380             : {
     381             : public:
     382             :         typedef Policy SetPolicy;
     383             : };
     384             : 
     385             : 
     386             : /// Needed by the user to set one of the policies
     387             : ///
     388             : /// @tparam Policy
     389             : template <typename Policy>
     390             : class ContextPolicyIs : virtual public DefaultPolicies
     391             : {
     392             : public:
     393             :         typedef Policy ContextPolicy;
     394             : };
     395             : 
     396             : 
     397             : /// Needed by the user to set one of the policies
     398             : ///
     399             : /// @tparam Policy
     400             : template <typename Policy>
     401             : class WritePolicyIs : virtual public DefaultPolicies
     402             : {
     403             : public:
     404             :         typedef Policy WritePolicy;
     405             : };
     406             : 
     407             : 
     408             : /// Needed by the user to set one of the policies
     409             : ///
     410             : /// @tparam Policy
     411             : template <typename Policy>
     412             : class ObserverPolicyIs : virtual public DefaultPolicies
     413             : {
     414             : public:
     415             :         typedef Policy ObserverPolicy;
     416             : };
     417             : 
     418             : 
     419             : /// Needed by the user to set one of the policies
     420             : ///
     421             : /// @tparam Policy
     422             : template <typename Policy>
     423             : class LockPolicyIs : virtual public DefaultPolicies
     424             : {
     425             : public:
     426             :         typedef Policy LockPolicy;
     427             : };
     428             : 
     429             : 
     430             : // standard types
     431             : 
     432             : template <typename T, typename PolicySetter1 = DefaultPolicyArgs, typename PolicySetter2 = DefaultPolicyArgs,
     433             :           typename PolicySetter3 = DefaultPolicyArgs, typename PolicySetter4 = DefaultPolicyArgs,
     434             :           typename PolicySetter5 = DefaultPolicyArgs, typename PolicySetter6 = DefaultPolicyArgs>
     435             : class Value : public ValueObserver, public ValueSubject, public Wrapped
     436             : {
     437             : public:
     438             :         typedef T type;
     439             : 
     440             :         typedef PolicySelector<PolicySetter1, PolicySetter2, PolicySetter3, PolicySetter4, PolicySetter5, PolicySetter6> Policies;
     441             : 
     442          36 :         Value (const Value &) = default;
     443             : 
     444             :         // not to be constructed yourself
     445         182 :         Value<T, PolicySetter1, PolicySetter2, PolicySetter3, PolicySetter4, PolicySetter5, PolicySetter6> (
     446             :                 KeySet & ks, typename Policies::ContextPolicy & context_, kdb::Key spec)
     447         596 :         : m_cache (), m_hasChanged (false), m_ks (ks), m_context (context_), m_spec (spec)
     448             :         {
     449             :                 assert (m_spec.getName ()[0] == '/' && "spec keys are not yet supported");
     450         364 :                 m_context.attachByName (m_spec.getName (), *this);
     451         908 :                 Command::Func fun = [this]() -> Command::Pair {
     452         920 :                         this->unsafeUpdateKeyUsingContext (m_context.evaluate (m_spec.getName ()));
     453         182 :                         this->unsafeSyncCache (); // set m_cache
     454         728 :                         return std::make_pair ("", m_key.getName ());
     455         546 :                 };
     456         546 :                 Command command (*this, fun);
     457         182 :                 m_context.execute (command);
     458         182 :         }
     459             : 
     460         188 :         ~Value<T, PolicySetter1, PolicySetter2, PolicySetter3, PolicySetter4, PolicySetter5, PolicySetter6> ()
     461             :         {
     462         376 :                 Command::Func fun = [this]() -> Command::Pair {
     463         376 :                         std::string oldName = m_key.getName ();
     464         376 :                         m_key = static_cast<ckdb::Key *> (nullptr);
     465             :                         // after destructor we do not need to care about
     466             :                         // invariant anymore. But we need to care about
     467             :                         // thread safe m_key.
     468         564 :                         return std::make_pair (oldName, "");
     469         564 :                 };
     470         564 :                 Command command (*this, fun);
     471         188 :                 m_context.execute (command);
     472         802 :         }
     473             : 
     474             :         typedef Value<T, PolicySetter1, PolicySetter2, PolicySetter3, PolicySetter4, PolicySetter5, PolicySetter6> V;
     475             : 
     476             :         V const & operator= (type n)
     477             :         {
     478             :                 static_assert (Policies::WritePolicy::allowed, "read only contextual value");
     479         174 :                 m_cache = n;
     480         148 :                 m_hasChanged = true;
     481         148 :                 syncKeySet ();
     482             : 
     483             :                 return *this;
     484             :         }
     485             : 
     486             :         type operator++ ()
     487             :         {
     488             :                 static_assert (Policies::WritePolicy::allowed, "read only contextual value");
     489             :                 type ret = ++m_cache;
     490             :                 m_hasChanged = true;
     491             :                 syncKeySet ();
     492             :                 return ret;
     493             :         }
     494             : 
     495             :         type operator++ (int)
     496             :         {
     497             :                 static_assert (Policies::WritePolicy::allowed, "read only contextual value");
     498             :                 type ret = m_cache++;
     499             :                 m_hasChanged = true;
     500             :                 syncKeySet ();
     501             :                 return ret;
     502             :         }
     503             : 
     504             :         type operator-- ()
     505             :         {
     506             :                 static_assert (Policies::WritePolicy::allowed, "read only contextual value");
     507           2 :                 type ret = --m_cache;
     508           2 :                 m_hasChanged = true;
     509           2 :                 syncKeySet ();
     510             :                 return ret;
     511             :         }
     512             : 
     513             :         type operator-- (int)
     514             :         {
     515             :                 static_assert (Policies::WritePolicy::allowed, "read only contextual value");
     516             :                 type ret = m_cache--;
     517             :                 m_hasChanged = true;
     518             :                 syncKeySet ();
     519             :                 return ret;
     520             :         }
     521             : 
     522             :         V & operator= (V const & rhs)
     523             :         {
     524             :                 static_assert (Policies::WritePolicy::allowed, "read only contextual value");
     525             :                 if (this != &rhs)
     526             :                 {
     527           2 :                         m_cache = rhs;
     528           2 :                         m_hasChanged = true;
     529           2 :                         syncKeySet ();
     530             :                 }
     531             :                 return *this;
     532             :         }
     533             : 
     534             : #define ELEKTRA_DEFINE_OPERATOR(op)                                                                                                        \
     535             :         V & operator op (type const & rhs)                                                                                                 \
     536             :         {                                                                                                                                  \
     537             :                 static_assert (Policies::WritePolicy::allowed, "read only contextual value");                                              \
     538             :                 m_cache op rhs;                                                                                                            \
     539             :                 m_hasChanged = true;                                                                                                       \
     540             :                 syncKeySet ();                                                                                                             \
     541             :                 return *this;                                                                                                              \
     542             :         }
     543             : 
     544           2 :         ELEKTRA_DEFINE_OPERATOR (-=)
     545           6 :         ELEKTRA_DEFINE_OPERATOR (+=)
     546           2 :         ELEKTRA_DEFINE_OPERATOR (*=)
     547           2 :         ELEKTRA_DEFINE_OPERATOR (/=)
     548           2 :         ELEKTRA_DEFINE_OPERATOR (%=)
     549             :         ELEKTRA_DEFINE_OPERATOR (^=)
     550             :         ELEKTRA_DEFINE_OPERATOR (&=)
     551           2 :         ELEKTRA_DEFINE_OPERATOR (|=)
     552             : 
     553             : #undef ELEKTRA_DEFINE_OPERATOR
     554             : 
     555             :         type operator- () const
     556             :         {
     557           4 :                 return -m_cache;
     558             :         }
     559             : 
     560             :         type operator~ () const
     561             :         {
     562           6 :                 return ~m_cache;
     563             :         }
     564             : 
     565             :         type operator! () const
     566             :         {
     567           6 :                 return !m_cache;
     568             :         }
     569             : 
     570             :         // type conversion
     571             :         operator type () const
     572             :         {
     573         194 :                 return m_cache;
     574             :         }
     575             : 
     576             :         /**
     577             :          * @return the context bound to the value
     578             :          */
     579             :         typename Policies::ContextPolicy & context () const
     580             :         {
     581             :                 /// We allow manipulation of context for const
     582             :                 /// objects
     583             :                 return const_cast<typename Policies::ContextPolicy &> (m_context);
     584             :         }
     585             : 
     586             :         /**
     587             :          * @brief Shortcut for context()
     588             :          *
     589             :          * @see context()
     590             :          */
     591             :         typename Policies::ContextPolicy & c () const
     592             :         {
     593             :                 return context ();
     594             :         }
     595             : 
     596             :         /**
     597             :          * @return Specification Key
     598             :          */
     599             :         Key const & getSpec () const
     600             :         {
     601           8 :                 return m_spec;
     602             :         }
     603             : 
     604             :         /**
     605             :          * @brief Returns the current name of contextual value
     606             :          *
     607             :          * @return name under contextual interpretation
     608             :          */
     609             :         std::string getName () const
     610             :         {
     611         276 :                 return m_key.getName ();
     612             :         }
     613             : 
     614         198 :         std::string layerId () const override
     615             :         {
     616        1188 :                 const Key meta = m_spec.getMeta<const Key> ("layer/name");
     617         198 :                 if (meta) return meta.getString ();
     618         168 :                 return m_spec.getBaseName ();
     619             :         }
     620             : 
     621          92 :         std::string layerVal () const override
     622             :         {
     623          92 :                 return m_key.getString ();
     624             :         }
     625             : 
     626             : 
     627             :         /**
     628             :          * @brief Sync key(set) to cache
     629             :          */
     630           4 :         void syncCache () const
     631             :         {
     632          16 :                 Command::Func fun = [this]() -> Command::Pair {
     633           8 :                         std::string const & oldKey = m_key.getName ();
     634           4 :                         this->unsafeLookupKey ();
     635           4 :                         this->unsafeSyncCache ();
     636          16 :                         return std::make_pair (oldKey, m_key.getName ());
     637          12 :                 };
     638          12 :                 Command command (*this, fun);
     639           4 :                 m_context.execute (command);
     640           4 :         }
     641             : 
     642             :         /**
     643             :          * @brief Sync cache to key(set)
     644             :          */
     645         184 :         void syncKeySet () const
     646             :         {
     647         552 :                 Command::Func fun = [this]() -> Command::Pair {
     648         368 :                         std::string const & oldKey = m_key.getName ();
     649         184 :                         this->unsafeSyncKeySet ();
     650         736 :                         return std::make_pair (oldKey, m_key.getName ());
     651         552 :                 };
     652         552 :                 Command command (*this, fun, m_hasChanged);
     653         184 :                 m_context.execute (command);
     654         184 :         }
     655             : 
     656             : private:
     657         556 :         void unsafeUpdateKeyUsingContext (std::string const & evaluatedName) const
     658             :         {
     659        2224 :                 Key spec (m_spec.dup ());
     660         556 :                 spec.setName (evaluatedName);
     661        1680 :                 m_key = Policies::GetPolicy::get (m_ks, spec);
     662             :                 assert (m_key);
     663         556 :         }
     664             : 
     665           4 :         void unsafeLookupKey () const
     666             :         {
     667             :                 // Key spec (m_spec.dup ());
     668             :                 // spec.setName (m_context.evaluate(m_spec.getName()));
     669             :                 // m_key = Policies::GetPolicy::get (m_ks, spec);
     670          12 :                 m_key = Policies::GetPolicy::get (m_ks, m_key);
     671             :                 assert (m_key);
     672           4 :         }
     673             : 
     674             :         /**
     675             :          * @brief Unsafe: Execute this method *only* in a Command execution
     676             :          */
     677         104 :         void unsafeSyncCache () const
     678             :         {
     679             :                 assert (m_key);
     680             : 
     681             : #if DEBUG && VERBOSE
     682             :                 std::cout << "will get name: " << m_key.getName () << " value: " << m_key.getString () << std::endl;
     683             : #endif
     684             : 
     685         798 :                 m_cache = m_key.get<type> ();
     686         104 :         }
     687             : 
     688             :         /**
     689             :          * @brief Execute this method *only* in a Command execution
     690             :          */
     691         510 :         void unsafeSyncKeySet () const
     692             :         {
     693         938 :                 if (m_hasChanged && m_key.getName ().at (0) == '/')
     694             :                 {
     695          96 :                         m_hasChanged = false;
     696         384 :                         Key spec (m_spec.dup ());
     697         192 :                         spec.setName (m_key.getName ());
     698         288 :                         m_key = Policies::SetPolicy::set (m_ks, spec);
     699             :                 }
     700             :                 assert (m_key);
     701         586 :                 m_key.set<type> (m_cache);
     702             : 
     703             : #if DEBUG && VERBOSE
     704             :                 std::cout << "set name: " << m_key.getName () << " value: " << m_key.getString () << std::endl;
     705             : #endif
     706         510 :         }
     707             : 
     708             :         /**
     709             :          * @brief Update to new value because of assignment
     710             :          */
     711          30 :         void notifyInThread () override
     712             :         {
     713          30 :                 unsafeSyncCache (); // always called from save context
     714          30 :         }
     715             : 
     716             : 
     717         398 :         virtual void updateContext (bool write) const override
     718             :         {
     719        1194 :                 std::string evaluatedName = m_context.evaluate (m_spec.getName ());
     720             : #if DEBUG && VERBOSE
     721             :                 std::cout << "update context " << evaluatedName << " from " << m_spec.getName () << " with write " << write << std::endl;
     722             : #endif
     723             : 
     724        2618 :                 Command::Func fun = [this, &evaluatedName, write]() -> Command::Pair {
     725         796 :                         std::string oldKey = m_key.getName ();
     726         748 :                         if (write && evaluatedName == oldKey)
     727             :                         {
     728             :                                 // nothing changed, same name
     729             :                                 return std::make_pair (evaluatedName, evaluatedName);
     730             :                         }
     731             : 
     732         374 :                         if (write)
     733             :                         {
     734         326 :                                 this->unsafeSyncKeySet (); // flush out what currently is in cache
     735             :                         }
     736             : 
     737         374 :                         this->unsafeUpdateKeyUsingContext (evaluatedName);
     738         374 :                         this->unsafeSyncCache (); // read what we have under new context
     739             : 
     740        1122 :                         return std::make_pair (oldKey, m_key.getName ());
     741         796 :                 };
     742        1194 :                 Command command (*this, fun);
     743         398 :                 m_context.execute (command);
     744         398 :         }
     745             : 
     746          60 :         virtual kdb::Key getDepKey () const override
     747             :         {
     748         180 :                 kdb::Key dep ("/" + layerId (), KEY_END);
     749             :                 // rename to /layer/order
     750         360 :                 const Key meta = m_spec.getMeta<const Key> ("layer/order");
     751          60 :                 if (meta)
     752             :                 {
     753          20 :                         dep.setMeta ("order", meta.getString ());
     754             :                 }
     755         344 :                 m_context.evaluate (m_spec.getName (), [&](std::string const & current_id, std::string &, bool) {
     756             : #if DEBUG && VERBOSE
     757             :                         std::cout << "add dep " << current_id << " to " << dep.getName () << std::endl;
     758             : #endif
     759         176 :                         ckdb::elektraMetaArrayAdd (*dep, "dep", ("/" + current_id).c_str ());
     760          44 :                         return false;
     761             :                 });
     762          60 :                 return dep;
     763             :         }
     764             : 
     765             : private:
     766             :         /**
     767             :          * @brief A transient mutable cache for very fast read-access.
     768             :          */
     769             :         mutable type m_cache;
     770             : 
     771             :         /**
     772             :          * @brief triggers transition from transient to persistent keys
     773             :          * @retval true if m_cache was changed
     774             :          */
     775             :         mutable bool m_hasChanged;
     776             : 
     777             :         /**
     778             :          * @brief Reference to the keyset in use
     779             :          *
     780             :          * only accessed using
     781             :          * Command, that might be multi-thread safe depending on
     782             :          * ContextPolicyIs
     783             :          */
     784             :         KeySet & m_ks;
     785             : 
     786             :         /**
     787             :          * @brief The context that might be
     788             :          *
     789             :          * - thread safe
     790             :          * - allow COP
     791             :          */
     792             :         typename Policies::ContextPolicy & m_context;
     793             : 
     794             :         /**
     795             :          * @brief The specification key
     796             :          *
     797             :          * Is only read and will not be changed.
     798             :          *
     799             :          * Might start with / or with spec/ (not implemented yet)
     800             :          */
     801             :         Key m_spec;
     802             : 
     803             :         /**
     804             :          * @brief The current key the Value is bound to.
     805             :          *
     806             :          * @invariant: Is never a null key
     807             :          */
     808             :         mutable Key m_key;
     809             : };
     810             : 
     811             : template <typename T, typename PolicySetter1, typename PolicySetter2, typename PolicySetter3, typename PolicySetter4,
     812             :           typename PolicySetter5, typename PolicySetter6>
     813             : std::ostream & operator<< (std::ostream & os,
     814             :                            Value<T, PolicySetter1, PolicySetter2, PolicySetter3, PolicySetter4, PolicySetter5, PolicySetter6> const & v)
     815             : {
     816           0 :         os << static_cast<T> (v);
     817             :         return os;
     818             : }
     819             : } // namespace kdb
     820             : 
     821             : #endif

Generated by: LCOV version 1.13