Chapter 21. Derived values

The following templates implement a derived value. A derived value is a reference-counted subclass of a very important object that sets is value based on a varying list of other values. A set of functors define how a varying list of values derives some value, of the same or a different type.

#include <x/derivedvalue.H>

typedef x::derivedvalue<int, std::string> derived_t;

derived_t derived=x::derivedvalues<int>::create(
        []
        {
            return (int)0;
        },
        []
        (int &sum, const int &v)
        {
            sum += v;
        },
        []
        (const int &sum)
        {
             std::ostringstream o;

             o << sum*2;
             return o.str();
        });

This example creates a x::w::derivedvalue that's a std::string which is derived from a list of ints. x::derivedvalues<int>::create() creates this reference-counted object. Its template parameter specifies the type of values the derived object gets derived from. Three lambdas, given as arguments to create() calculate the derived value.

The type that the final value returns sets the type of the very important derived value. The above example creates a std::string from a list of ints by adding them together, multiplying the sum by two, and converting it to a std::string.

Note

The calculated derived value gets compared to the current derived value using the == operator. Only if the newly calculated derived value does not compare as equal, does this this still result in an update to the derived value, and invocation of all the registered lambda callbacks.

x::derivedvaluelist<int>::base::current_value_t
    v=derived->create(1);
      

This create() method adds a new value to the list of values that the derived value gets calculated from. current_value_t is also a reference to a reference-counted object. The initial value, of the added value, gets passed to create()'s constructor. There's also an emplace() method that constructs a new value.

	v=derived->create(1);
      

The derived value gets automatically recalculated whenever:

Any of these events result in invoking the three lambdas to calculate a new derived value based on the updated list of values that the derived value is based on.

typedef derived_value_t::base::vipobj_t vipobj_t;

vipobj_t::handlerlock lock(*derived);

std::string current_value=*vipobj_t::readlock(*derived);

auto mcguffin=lock->install_back([]
                                 (const std::string &value)
                                 {
                                 },
                                 current_value);

x::derivedvalue<value_type, derived_value_type>::base::vipobj_t gives the type of the x::vipobj that the derived value is based on. Use a handler lock to register callback lambdas to obtain the value of the derived value.

Note

The derived value object takes complete responsibility for using the underlying update lock and write lock, to set the new calculated value. These locks should not be used explicitly.

Note

Each current_value_t holds a reference to its derivedvalue, and it's not specified in which order each value gets passed to the calculation lmabda, during the calculation.