summaryrefslogtreecommitdiff
path: root/include/CommonAPI/Extensions/AttributeCacheExtension.hpp
blob: 051bb094392516c7e5f4cf6aa2636525d39ae7e3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef COMMONAPI_EXTENSIONS_ATTRIBUTE_CACHE_EXTENSION_HPP_
#define COMMONAPI_EXTENSIONS_ATTRIBUTE_CACHE_EXTENSION_HPP_

#include <CommonAPI/CommonAPI.hpp>

#include <memory>
#include <type_traits>

namespace CommonAPI {
namespace Extensions {

namespace AttributeCache {
template<typename AttributeType_>
struct AttributeTraits;

template<typename AttributeType_, bool>
class AttributeCacheExtensionImpl;
}

template <typename AttributeType_>
using AttributeCacheExtension = AttributeCache::AttributeCacheExtensionImpl<AttributeType_,
                                                                            AttributeCache::AttributeTraits<AttributeType_>::observable>;

namespace AttributeCache {

template<typename AttributeType_>
struct AttributeTraits {
    static const bool observable = (std::is_base_of<
                                            CommonAPI::ObservableAttribute<
                                                    typename AttributeType_::ValueType>,
                                            AttributeType_>::value
                                            || std::is_base_of<
                                                    CommonAPI::ObservableReadonlyAttribute<
                                                            typename AttributeType_::ValueType>,
                                                    AttributeType_>::value);
};

template<typename AttributeType_>
class AttributeCacheExtensionImpl<AttributeType_, false> : public CommonAPI::AttributeExtension<
        AttributeType_> {
protected:
    typedef CommonAPI::AttributeExtension<AttributeType_> __baseClass_t;

    typedef typename AttributeType_::ValueType value_t;

public:
    AttributeCacheExtensionImpl(AttributeType_& baseAttribute)
            : CommonAPI::AttributeExtension<AttributeType_>(baseAttribute) {
    }

};

template<typename AttributeType_>
class AttributeCacheExtensionImpl<AttributeType_, true> : public CommonAPI::AttributeExtension<
        AttributeType_> {
    typedef CommonAPI::AttributeExtension<AttributeType_> __baseClass_t;

protected:
    typedef typename AttributeType_::ValueType value_t;
    typedef std::shared_ptr<const value_t> valueptr_t;

public:
    AttributeCacheExtensionImpl(AttributeType_& baseAttribute)
            : CommonAPI::AttributeExtension<AttributeType_>(baseAttribute) {
        auto &event = __baseClass_t::getBaseAttribute().getChangedEvent();
        event.subscribe(
                std::bind(
                        &AttributeCacheExtensionImpl<AttributeType_, true>::onValueUpdate,
                        this, std::placeholders::_1));
    }

    /**
     * @brief getCachedValue Retrieve attribute value from the cache
     * @return The value of the attribute or a null pointer if the value is not
     *         yet available. Retrieving a non-cached value will trigger
     *         retrieval of the value. Changes to the cached value are emitted
     *         via the getChangedEvent.
     */
    valueptr_t getCachedValue() {
        if (cachedValue_) {
            return cachedValue_;
        }

        return nullptr;
    }

    /**
     * @brief getCachedValue Retrieve attribute value from the cache returning a
     *                       default value if the cache was empty.
     * @param errorValue The value to return if the value could not be found in
     *                   the cache.
     * @return The value of the attribute or errorValue.
     */
    valueptr_t getCachedValue(const value_t &errorValue) {
        valueptr_t result = getCachedValue();

        if (!result)
            result = std::make_shared<const value_t>(errorValue);

        return result;
    }

private:

    void valueRetrieved(const CommonAPI::CallStatus &callStatus, value_t t) {
        if (callStatus == CommonAPI::CallStatus::SUCCESS) {
            onValueUpdate(t);
        }
    }

    void onValueUpdate(const value_t& t) {
        if (cachedValue_ && *cachedValue_ == t) {
            return;
        }

        cachedValue_ = std::make_shared<const value_t>(t);
    }

    valueptr_t cachedValue_;
};

} // namespace AttributeCache
} // namespace Extensions
} // namespace CommonAPI

#endif // COMMONAPI_EXTENSIONS_ATTRIBUTE_CACHE_EXTENSION_HPP_